133 lines
2.8 KiB
Go
133 lines
2.8 KiB
Go
// SPDX-FileCopyrightText: 2022-2023 nervuri <https://nervuri.net/contact>
|
|
//
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package clienthello
|
|
|
|
import (
|
|
_ "embed"
|
|
"encoding/csv"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// RFC 8446, Section 4.2.7
|
|
// https://www.rfc-editor.org/rfc/rfc8446.html#section-4.2.7
|
|
// https://www.iana.org/assignments/tls-parameters/tls-parameters-8.csv
|
|
//
|
|
//go:embed named-groups.csv
|
|
var namedGroupsCSV string
|
|
|
|
var NamedGroupList = parseNamedGroupsCSV()
|
|
|
|
type NamedGroup any // (uint16 | NamedGroupInfo)
|
|
|
|
type NamedGroupInfo struct {
|
|
Code uint16 `json:"code"`
|
|
HexCode string `json:"hex_code"`
|
|
Name string `json:"name"`
|
|
Recommended bool `json:"-"`
|
|
Reference string `json:"-"`
|
|
}
|
|
|
|
// TLS 1.3 Key Share. See RFC 8446, Section 4.2.8.
|
|
type KeyShare struct {
|
|
Group NamedGroup `json:"group"`
|
|
Data byteSlice `json:"data"`
|
|
}
|
|
|
|
func parseNamedGroupsCSV() map[uint16]NamedGroupInfo {
|
|
namedGroups := map[uint16]NamedGroupInfo{}
|
|
r := csv.NewReader(strings.NewReader(namedGroupsCSV))
|
|
|
|
// Skip CSV header.
|
|
_, err := r.Read()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
for {
|
|
row, err := r.Read()
|
|
if err == io.EOF {
|
|
break
|
|
} else if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
var (
|
|
val = row[0]
|
|
desc = row[1]
|
|
rec = row[3]
|
|
ref = row[4]
|
|
)
|
|
if desc == "Unassigned" {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(desc, "Reserved") && ref != "[RFC8701]" {
|
|
continue
|
|
}
|
|
code, err := strconv.Atoi(val)
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
group := NamedGroupInfo{
|
|
Code: uint16(code),
|
|
HexCode: fmt.Sprintf("%04X", code),
|
|
Name: desc,
|
|
Reference: ref,
|
|
}
|
|
if rec == "Y" {
|
|
group.Recommended = true
|
|
}
|
|
if ref == "[RFC8701]" {
|
|
group.Name = "GREASE"
|
|
}
|
|
|
|
namedGroups[group.Code] = group
|
|
}
|
|
return namedGroups
|
|
}
|
|
|
|
func GetNamedGroupInfo(namedGroupCode uint16, mustName bool) NamedGroupInfo {
|
|
info, found := NamedGroupList[namedGroupCode]
|
|
if !found {
|
|
info = NamedGroupInfo{
|
|
Code: namedGroupCode,
|
|
HexCode: fmt.Sprintf("%04X", namedGroupCode),
|
|
}
|
|
}
|
|
if mustName && info.Name == "" {
|
|
info.Name = "0x" + info.HexCode
|
|
}
|
|
return info
|
|
}
|
|
|
|
func (m *ClientHelloMsg) AddNamedGroupInfo() {
|
|
for i, ext := range m.Extensions {
|
|
switch ext.Code {
|
|
case extensionSupportedGroups:
|
|
for j, group := range ext.Data.SupportedGroups {
|
|
m.Extensions[i].Data.SupportedGroups[j] =
|
|
GetNamedGroupInfo(group.(uint16), false)
|
|
}
|
|
case extensionKeyShare:
|
|
for j, kShare := range ext.Data.KeyShares {
|
|
m.Extensions[i].Data.KeyShares[j].Group =
|
|
GetNamedGroupInfo(kShare.Group.(uint16), false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *ClientHelloMsg) GetSupportedGroups() []NamedGroup {
|
|
var supportedGroups []NamedGroup
|
|
for _, ext := range m.Extensions {
|
|
if ext.Code == extensionSupportedGroups {
|
|
supportedGroups = append(supportedGroups, ext.Data.SupportedGroups...)
|
|
}
|
|
}
|
|
return supportedGroups
|
|
}
|