tls_client_hello: Nim parsing library

KS implementation details

License: MIT

References

This page hosts a formal specification of tls_client_hello using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Nim source code to parse tls_client_hello

tls_client_hello.nim

import kaitai_struct_nim_runtime
import options

type
  TlsClientHello* = ref object of KaitaiStruct
    `version`*: TlsClientHello_Version
    `random`*: TlsClientHello_Random
    `sessionId`*: TlsClientHello_SessionId
    `cipherSuites`*: TlsClientHello_CipherSuites
    `compressionMethods`*: TlsClientHello_CompressionMethods
    `extensions`*: TlsClientHello_Extensions
    `parent`*: KaitaiStruct
  TlsClientHello_ServerName* = ref object of KaitaiStruct
    `nameType`*: uint8
    `length`*: uint16
    `hostName`*: seq[byte]
    `parent`*: TlsClientHello_Sni
  TlsClientHello_Random* = ref object of KaitaiStruct
    `gmtUnixTime`*: uint32
    `random`*: seq[byte]
    `parent`*: TlsClientHello
  TlsClientHello_SessionId* = ref object of KaitaiStruct
    `len`*: uint8
    `sid`*: seq[byte]
    `parent`*: TlsClientHello
  TlsClientHello_Sni* = ref object of KaitaiStruct
    `listLength`*: uint16
    `serverNames`*: seq[TlsClientHello_ServerName]
    `parent`*: TlsClientHello_Extension
  TlsClientHello_CipherSuites* = ref object of KaitaiStruct
    `len`*: uint16
    `cipherSuites`*: seq[uint16]
    `parent`*: TlsClientHello
  TlsClientHello_CompressionMethods* = ref object of KaitaiStruct
    `len`*: uint8
    `compressionMethods`*: seq[byte]
    `parent`*: TlsClientHello
  TlsClientHello_Alpn* = ref object of KaitaiStruct
    `extLen`*: uint16
    `alpnProtocols`*: seq[TlsClientHello_Protocol]
    `parent`*: TlsClientHello_Extension
  TlsClientHello_Extensions* = ref object of KaitaiStruct
    `len`*: uint16
    `extensions`*: seq[TlsClientHello_Extension]
    `parent`*: TlsClientHello
  TlsClientHello_Version* = ref object of KaitaiStruct
    `major`*: uint8
    `minor`*: uint8
    `parent`*: TlsClientHello
  TlsClientHello_Protocol* = ref object of KaitaiStruct
    `strlen`*: uint8
    `name`*: seq[byte]
    `parent`*: TlsClientHello_Alpn
  TlsClientHello_Extension* = ref object of KaitaiStruct
    `type`*: uint16
    `len`*: uint16
    `body`*: KaitaiStruct
    `parent`*: TlsClientHello_Extensions
    `rawBody`*: seq[byte]

proc read*(_: typedesc[TlsClientHello], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): TlsClientHello
proc read*(_: typedesc[TlsClientHello_ServerName], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Sni): TlsClientHello_ServerName
proc read*(_: typedesc[TlsClientHello_Random], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_Random
proc read*(_: typedesc[TlsClientHello_SessionId], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_SessionId
proc read*(_: typedesc[TlsClientHello_Sni], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Extension): TlsClientHello_Sni
proc read*(_: typedesc[TlsClientHello_CipherSuites], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_CipherSuites
proc read*(_: typedesc[TlsClientHello_CompressionMethods], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_CompressionMethods
proc read*(_: typedesc[TlsClientHello_Alpn], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Extension): TlsClientHello_Alpn
proc read*(_: typedesc[TlsClientHello_Extensions], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_Extensions
proc read*(_: typedesc[TlsClientHello_Version], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_Version
proc read*(_: typedesc[TlsClientHello_Protocol], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Alpn): TlsClientHello_Protocol
proc read*(_: typedesc[TlsClientHello_Extension], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Extensions): TlsClientHello_Extension


proc read*(_: typedesc[TlsClientHello], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): TlsClientHello =
  template this: untyped = result
  this = new(TlsClientHello)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let versionExpr = TlsClientHello_Version.read(this.io, this.root, this)
  this.version = versionExpr
  let randomExpr = TlsClientHello_Random.read(this.io, this.root, this)
  this.random = randomExpr
  let sessionIdExpr = TlsClientHello_SessionId.read(this.io, this.root, this)
  this.sessionId = sessionIdExpr
  let cipherSuitesExpr = TlsClientHello_CipherSuites.read(this.io, this.root, this)
  this.cipherSuites = cipherSuitesExpr
  let compressionMethodsExpr = TlsClientHello_CompressionMethods.read(this.io, this.root, this)
  this.compressionMethods = compressionMethodsExpr
  if this.io.isEof == false:
    let extensionsExpr = TlsClientHello_Extensions.read(this.io, this.root, this)
    this.extensions = extensionsExpr

proc fromFile*(_: typedesc[TlsClientHello], filename: string): TlsClientHello =
  TlsClientHello.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_ServerName], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Sni): TlsClientHello_ServerName =
  template this: untyped = result
  this = new(TlsClientHello_ServerName)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let nameTypeExpr = this.io.readU1()
  this.nameType = nameTypeExpr
  let lengthExpr = this.io.readU2be()
  this.length = lengthExpr
  let hostNameExpr = this.io.readBytes(int(this.length))
  this.hostName = hostNameExpr

proc fromFile*(_: typedesc[TlsClientHello_ServerName], filename: string): TlsClientHello_ServerName =
  TlsClientHello_ServerName.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_Random], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_Random =
  template this: untyped = result
  this = new(TlsClientHello_Random)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let gmtUnixTimeExpr = this.io.readU4be()
  this.gmtUnixTime = gmtUnixTimeExpr
  let randomExpr = this.io.readBytes(int(28))
  this.random = randomExpr

proc fromFile*(_: typedesc[TlsClientHello_Random], filename: string): TlsClientHello_Random =
  TlsClientHello_Random.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_SessionId], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_SessionId =
  template this: untyped = result
  this = new(TlsClientHello_SessionId)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let lenExpr = this.io.readU1()
  this.len = lenExpr
  let sidExpr = this.io.readBytes(int(this.len))
  this.sid = sidExpr

proc fromFile*(_: typedesc[TlsClientHello_SessionId], filename: string): TlsClientHello_SessionId =
  TlsClientHello_SessionId.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_Sni], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Extension): TlsClientHello_Sni =
  template this: untyped = result
  this = new(TlsClientHello_Sni)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let listLengthExpr = this.io.readU2be()
  this.listLength = listLengthExpr
  block:
    var i: int
    while not this.io.isEof:
      let it = TlsClientHello_ServerName.read(this.io, this.root, this)
      this.serverNames.add(it)
      inc i

proc fromFile*(_: typedesc[TlsClientHello_Sni], filename: string): TlsClientHello_Sni =
  TlsClientHello_Sni.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_CipherSuites], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_CipherSuites =
  template this: untyped = result
  this = new(TlsClientHello_CipherSuites)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let lenExpr = this.io.readU2be()
  this.len = lenExpr
  for i in 0 ..< int((this.len div 2)):
    let it = this.io.readU2be()
    this.cipherSuites.add(it)

proc fromFile*(_: typedesc[TlsClientHello_CipherSuites], filename: string): TlsClientHello_CipherSuites =
  TlsClientHello_CipherSuites.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_CompressionMethods], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_CompressionMethods =
  template this: untyped = result
  this = new(TlsClientHello_CompressionMethods)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let lenExpr = this.io.readU1()
  this.len = lenExpr
  let compressionMethodsExpr = this.io.readBytes(int(this.len))
  this.compressionMethods = compressionMethodsExpr

proc fromFile*(_: typedesc[TlsClientHello_CompressionMethods], filename: string): TlsClientHello_CompressionMethods =
  TlsClientHello_CompressionMethods.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_Alpn], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Extension): TlsClientHello_Alpn =
  template this: untyped = result
  this = new(TlsClientHello_Alpn)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let extLenExpr = this.io.readU2be()
  this.extLen = extLenExpr
  block:
    var i: int
    while not this.io.isEof:
      let it = TlsClientHello_Protocol.read(this.io, this.root, this)
      this.alpnProtocols.add(it)
      inc i

proc fromFile*(_: typedesc[TlsClientHello_Alpn], filename: string): TlsClientHello_Alpn =
  TlsClientHello_Alpn.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_Extensions], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_Extensions =
  template this: untyped = result
  this = new(TlsClientHello_Extensions)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let lenExpr = this.io.readU2be()
  this.len = lenExpr
  block:
    var i: int
    while not this.io.isEof:
      let it = TlsClientHello_Extension.read(this.io, this.root, this)
      this.extensions.add(it)
      inc i

proc fromFile*(_: typedesc[TlsClientHello_Extensions], filename: string): TlsClientHello_Extensions =
  TlsClientHello_Extensions.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_Version], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello): TlsClientHello_Version =
  template this: untyped = result
  this = new(TlsClientHello_Version)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let majorExpr = this.io.readU1()
  this.major = majorExpr
  let minorExpr = this.io.readU1()
  this.minor = minorExpr

proc fromFile*(_: typedesc[TlsClientHello_Version], filename: string): TlsClientHello_Version =
  TlsClientHello_Version.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_Protocol], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Alpn): TlsClientHello_Protocol =
  template this: untyped = result
  this = new(TlsClientHello_Protocol)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let strlenExpr = this.io.readU1()
  this.strlen = strlenExpr
  let nameExpr = this.io.readBytes(int(this.strlen))
  this.name = nameExpr

proc fromFile*(_: typedesc[TlsClientHello_Protocol], filename: string): TlsClientHello_Protocol =
  TlsClientHello_Protocol.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[TlsClientHello_Extension], io: KaitaiStream, root: KaitaiStruct, parent: TlsClientHello_Extensions): TlsClientHello_Extension =
  template this: untyped = result
  this = new(TlsClientHello_Extension)
  let root = if root == nil: cast[TlsClientHello](this) else: cast[TlsClientHello](root)
  this.io = io
  this.root = root
  this.parent = parent

  let typeExpr = this.io.readU2be()
  this.type = typeExpr
  let lenExpr = this.io.readU2be()
  this.len = lenExpr
  block:
    let on = this.type
    if on == 0:
      let rawBodyExpr = this.io.readBytes(int(this.len))
      this.rawBody = rawBodyExpr
      let rawBodyIo = newKaitaiStream(rawBodyExpr)
      let bodyExpr = TlsClientHello_Sni.read(rawBodyIo, this.root, this)
      this.body = bodyExpr
    elif on == 16:
      let rawBodyExpr = this.io.readBytes(int(this.len))
      this.rawBody = rawBodyExpr
      let rawBodyIo = newKaitaiStream(rawBodyExpr)
      let bodyExpr = TlsClientHello_Alpn.read(rawBodyIo, this.root, this)
      this.body = bodyExpr
    else:
      let bodyExpr = this.io.readBytes(int(this.len))
      this.body = bodyExpr

proc fromFile*(_: typedesc[TlsClientHello_Extension], filename: string): TlsClientHello_Extension =
  TlsClientHello_Extension.read(newKaitaiFileStream(filename), nil, nil)