Skip to content

Commit

Permalink
Merge pull request #7201 from TheThingsNetwork/feature/ttgc-claiming
Browse files Browse the repository at this point in the history
Claim gateways on The Things Gateway Controller
  • Loading branch information
johanstokking authored Aug 1, 2024
2 parents 13d2ea3 + 3e73593 commit 15ddbd9
Show file tree
Hide file tree
Showing 26 changed files with 609 additions and 191 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ For details about compatibility between different releases, see the **Commitment

### Added

- Support for managed gateways through The Things Gateway Controller.
- Support for managed gateways and claiming through The Things Gateway Controller.
- Support for The Things Industries gateway protocol. This is adds a new pair of ports to Gateway Server: `1889` for Envoy or Traefik terminated TLS mutual authentication, and `8889` for The Things Stack terminated TLS mutual authentication.

### Changed
Expand Down
1 change: 1 addition & 0 deletions api/ttn/lorawan/v3/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3100,6 +3100,7 @@ DEPRECATED: This message is deprecated and will be removed in a future version o
| ----- | ---- | ----- | ----------- |
| `eui` | [`bytes`](#bytes) | | |
| `supports_claiming` | [`bool`](#bool) | | |
| `is_managed` | [`bool`](#bool) | | Indicates whether the gateway is a managed gateway. If true, when the gateway is successfully claimed, it can be managed with ManagedGatewayConfigurationService. |

#### Field Rules

Expand Down
4 changes: 4 additions & 0 deletions api/ttn/lorawan/v3/api.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -24696,6 +24696,10 @@
},
"supports_claiming": {
"type": "boolean"
},
"is_managed": {
"type": "boolean",
"description": "Indicates whether the gateway is a managed gateway.\nIf true, when the gateway is successfully claimed, it can be managed with ManagedGatewayConfigurationService."
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions api/ttn/lorawan/v3/deviceclaimingserver.proto
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@ message GetInfoByGatewayEUIResponse {
}
];
bool supports_claiming = 2;
// Indicates whether the gateway is a managed gateway.
// If true, when the gateway is successfully claimed, it can be managed with ManagedGatewayConfigurationService.
bool is_managed = 3;
}

// The GatewayClaimingServer service support claiming and managing gateway claims.
Expand Down
24 changes: 21 additions & 3 deletions config/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3923,13 +3923,22 @@
"file": "ttjs.go"
}
},
"error:pkg/deviceclaimingserver/gateways/ttgc:not_implemented": {
"error:pkg/deviceclaimingserver/gateways/ttgc:dial_gateway_server": {
"translations": {
"en": "not implemented"
"en": "dial Gateway Gerver"
},
"description": {
"package": "pkg/deviceclaimingserver/gateways/ttgc",
"file": "ttgc.go"
"file": "root_ca.go"
}
},
"error:pkg/deviceclaimingserver/gateways/ttgc:gateway_server_tls": {
"translations": {
"en": "establish TLS connection with Gateway Server"
},
"description": {
"package": "pkg/deviceclaimingserver/gateways/ttgc",
"file": "root_ca.go"
}
},
"error:pkg/deviceclaimingserver/gateways:invalid_upstream": {
Expand All @@ -3941,6 +3950,15 @@
"file": "gateways.go"
}
},
"error:pkg/deviceclaimingserver/gateways:ttgc_not_enabled": {
"translations": {
"en": "TTGC is not enabled"
},
"description": {
"package": "pkg/deviceclaimingserver/gateways",
"file": "gateways.go"
}
},
"error:pkg/deviceclaimingserver:claim gateway": {
"translations": {
"en": "claim gateway"
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ require (
go.packetbroker.org/api/mapping/v2 v2.3.2
go.packetbroker.org/api/routing v1.9.2
go.packetbroker.org/api/v3 v3.17.1
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240723094213-b40a14f3b543
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd
go.thethings.industries/pkg/ca v0.0.0-20240723151912-b9bb4097ae6c
go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e
go.thethings.network/lorawan-stack-legacy/v2 v2.1.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,8 @@ go.packetbroker.org/api/routing v1.9.2 h1:J4+4vYZxa60UWC70Y9yy7sktU7DXaAp9Q13Bfq
go.packetbroker.org/api/routing v1.9.2/go.mod h1:kd2K7gieDI35YfPA8/zDmLX3qiKPuXia/MA77BEAeUA=
go.packetbroker.org/api/v3 v3.17.1 h1:LcyFPUGqVubGWMvQ16tZlQIKd+noGx7urzEYhSLiEQA=
go.packetbroker.org/api/v3 v3.17.1/go.mod h1:6bVbdWAYLnvZ5kgXxA7GBQvZTN7vxI0DoF1Di1NoAT4=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240723094213-b40a14f3b543 h1:CpDA1J3O/krqQrPypf+ePIV5xiLyy9RIayLXRnxiDSI=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240723094213-b40a14f3b543/go.mod h1:2+WsMwIunNLh22oauBzGL56JazE3UY34W1fstqEbacw=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd h1:FvD516hdD/iWqoS20SFdcoiUgwRJP3egNXNiN+Ux2d0=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd/go.mod h1:2+WsMwIunNLh22oauBzGL56JazE3UY34W1fstqEbacw=
go.thethings.industries/pkg/ca v0.0.0-20240723151912-b9bb4097ae6c h1:QkZ+O889SvaXAoJdIu2hyrAXvlIfuHDWOmlpOh97RHg=
go.thethings.industries/pkg/ca v0.0.0-20240723151912-b9bb4097ae6c/go.mod h1:89OU623VYKW9i3W4CZgIGFmtgb/jsN8JV2PAuCsj+7w=
go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e h1:TWGQ3lh7gI2W5hnb6qPdpoAa0d7s/XPwvgf2VVCMJaY=
Expand Down
2 changes: 1 addition & 1 deletion pkg/deviceclaimingserver/deviceclaimingserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func New(c *component.Component, conf *Config, opts ...Option) (*DeviceClaimingS
}

if dcs.grpc.gatewayClaimingServer == nil {
upstream, err := gateways.NewUpstream(ctx, conf.GatewayClaimingServerConfig)
upstream, err := gateways.NewUpstream(ctx, c, conf.GatewayClaimingServerConfig)
if err != nil {
return nil, err
}
Expand Down
42 changes: 35 additions & 7 deletions pkg/deviceclaimingserver/gateways/gateways.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,39 @@ package gateways

import (
"context"
"crypto/tls"
"strings"

"go.thethings.network/lorawan-stack/v3/pkg/config"
"go.thethings.network/lorawan-stack/v3/pkg/config/tlsconfig"
"go.thethings.network/lorawan-stack/v3/pkg/deviceclaimingserver/gateways/ttgc"
dcstypes "go.thethings.network/lorawan-stack/v3/pkg/deviceclaimingserver/types"
"go.thethings.network/lorawan-stack/v3/pkg/errors"
"go.thethings.network/lorawan-stack/v3/pkg/types"
)

// Component is the interface to the component.
type Component interface {
GetBaseConfig(context.Context) config.ServiceBase
GetTLSClientConfig(context.Context, ...tlsconfig.Option) (*tls.Config, error)
}

// Config is the configuration for the Gateway Claiming Server.
type Config struct {
CreateOnNotFound bool `name:"create-on-not-found" description:"DEPRECATED"` // nolint:lll
DefaultGatewayServerAddress string `name:"default-gateway-server-address" description:"The default Gateway Server Address"` // nolint:lll
Upstreams map[string][]string `name:"upstreams" description:"Map of upstream type and the supported Gateway EUI ranges"` // nolint:lll
TTGC ttgc.Config `name:"ttgc"`
}

var errInvalidUpstream = errors.DefineInvalidArgument("invalid_upstream", "upstream `{name}` is invalid")
var (
errInvalidUpstream = errors.DefineInvalidArgument("invalid_upstream", "upstream `{name}` is invalid")
errTTGCNotEnabled = errors.DefineFailedPrecondition("ttgc_not_enabled", "TTGC is not enabled")
)

// ParseGatewayEUIRanges parses the configured upstream map and returns map of ranges.
func ParseGatewayEUIRanges(config map[string][]string) (map[string][]dcstypes.EUI64Range, error) {
res := make(map[string][]dcstypes.EUI64Range, len(config))
for host, ranges := range config {
func ParseGatewayEUIRanges(conf map[string][]string) (map[string][]dcstypes.EUI64Range, error) {
res := make(map[string][]dcstypes.EUI64Range, len(conf))
for host, ranges := range conf {
res[host] = make([]dcstypes.EUI64Range, 0, len(ranges))
for _, val := range ranges {
var r dcstypes.EUI64Range
Expand Down Expand Up @@ -76,7 +87,9 @@ type Claimer interface {
// Claim claims a gateway.
Claim(ctx context.Context, eui types.EUI64, ownerToken string, clusterAddress string) error
// Unclaim unclaims a gateway.
Unclaim(context.Context, types.EUI64, string) error
Unclaim(ctx context.Context, eui types.EUI64) error
// IsManagedGateway returns true if the gateway is a managed gateway.
IsManagedGateway(ctx context.Context, eui types.EUI64) (bool, error)
}

// rangeClaimer supports claiming a range of EUIs.
Expand All @@ -93,6 +106,7 @@ type Upstream struct {
// NewUpstream returns a new upstream based on the provided configuration.
func NewUpstream(
ctx context.Context,
c Component,
conf Config,
opts ...Option,
) (*Upstream, error) {
Expand All @@ -107,6 +121,17 @@ func NewUpstream(
if err != nil {
return nil, err
}

// Implicitly add TTGC if it is enabled and not already configured.
ttgcConf := c.GetBaseConfig(ctx).TTGC
if _, ttgcAdded := hosts["ttgc"]; ttgcConf.Enabled && !ttgcAdded {
ttgcRanges := make([]dcstypes.EUI64Range, len(ttgcConf.GatewayEUIs))
for i, prefix := range ttgcConf.GatewayEUIs {
ttgcRanges[i] = dcstypes.RangeFromEUI64Prefix(prefix)
}
hosts["ttgc"] = ttgcRanges
}

// Setup upstream table.
for name, ranges := range hosts {
if len(ranges) == 0 || name == "" {
Expand All @@ -115,7 +140,10 @@ func NewUpstream(
var claimer Claimer
switch name {
case "ttgc":
claimer, err = conf.TTGC.NewClient(ctx)
if !ttgcConf.Enabled {
return nil, errTTGCNotEnabled.New()
}
claimer, err = ttgc.New(ctx, c, ttgcConf)
if err != nil {
return nil, err
}
Expand Down
40 changes: 30 additions & 10 deletions pkg/deviceclaimingserver/gateways/gateways_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ package gateways_test
import (
"testing"

"go.thethings.network/lorawan-stack/v3/pkg/component"
componenttest "go.thethings.network/lorawan-stack/v3/pkg/component/test"
"go.thethings.network/lorawan-stack/v3/pkg/config"
"go.thethings.network/lorawan-stack/v3/pkg/config/tlsconfig"
"go.thethings.network/lorawan-stack/v3/pkg/deviceclaimingserver/gateways"
"go.thethings.network/lorawan-stack/v3/pkg/deviceclaimingserver/gateways/ttgc"
dcstypes "go.thethings.network/lorawan-stack/v3/pkg/deviceclaimingserver/types"
"go.thethings.network/lorawan-stack/v3/pkg/errors"
"go.thethings.network/lorawan-stack/v3/pkg/ttgc"
"go.thethings.network/lorawan-stack/v3/pkg/types"
"go.thethings.network/lorawan-stack/v3/pkg/util/test"
"go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should"
Expand All @@ -31,6 +35,25 @@ func TestUpstream(t *testing.T) {

a, ctx := test.New(t)

c := componenttest.NewComponent(t, &component.Config{
ServiceBase: config.ServiceBase{
TTGC: ttgc.Config{
Enabled: true,
GatewayEUIs: []types.EUI64Prefix{
{
EUI64: types.EUI64{0x58, 0xa0, 0xcb, 0xff, 0xfe, 0x80, 0x00, 0x00},
Length: 48,
},
},
TLS: tlsconfig.ClientAuth{
Source: "file",
Certificate: "testdata/client.pem",
Key: "testdata/client-key.pem",
},
},
},
})

// Invalid ranges.
ranges := map[string][]string{"ttgc": {"&S(FU*)"}}
euiPrefixes, err := gateways.ParseGatewayEUIRanges(ranges)
Expand Down Expand Up @@ -85,28 +108,25 @@ func TestUpstream(t *testing.T) {
})

// Invalid configurations
config := gateways.Config{
conf := gateways.Config{
Upstreams: map[string][]string{"ttgc": {"&S(FU*)"}},
TTGC: ttgc.Config{},
}
upstream, err := gateways.NewUpstream(ctx, config)
upstream, err := gateways.NewUpstream(ctx, c, conf)
a.So(errors.IsInvalidArgument(err), should.BeTrue)
a.So(upstream, should.BeNil)

config = gateways.Config{
conf = gateways.Config{
Upstreams: map[string][]string{"unsupported": {"58A0CBFFFE800000/48"}},
TTGC: ttgc.Config{},
}
upstream, err = gateways.NewUpstream(ctx, config)
upstream, err = gateways.NewUpstream(ctx, c, conf)
a.So(errors.IsInvalidArgument(err), should.BeTrue)
a.So(upstream, should.BeNil)

// Valid Configuration
config = gateways.Config{
conf = gateways.Config{
Upstreams: map[string][]string{"ttgc": {"58A0CBFFFE800000/48"}},
TTGC: ttgc.Config{},
}
upstream, err = gateways.NewUpstream(ctx, config)
upstream, err = gateways.NewUpstream(ctx, c, conf)
a.So(err, should.BeNil)
a.So(upstream, should.NotBeNil)

Expand Down
28 changes: 28 additions & 0 deletions pkg/deviceclaimingserver/gateways/testdata/client-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDF+is3SbxVrjeO
yooAeJfjAD9GylMI5Z4cfHjPgeTf2bZlfVnmx+q5rdrN6B/cQo1BEIqFHZ9B6oqx
CZUgBBg9yZx12XjQk4kWvGhEnuHfJI3c188iZdUt6aJHITKaGGkbu6JJzaJ+eUl+
pa4Ghae4gsP5qOgsp03LdSAZXByeP9E1nFu9MR1lJCfI2sBLoHLEIh3pA6YPhRvL
/aPBeCdKqnTVce61YnXxQQVHrA82smeICHRvx1KQWkvN7Y0icDSBh74vsRaaO+zP
suHTR5EmpmqNX5VZosoUrNCQHddAvQwBGZv/ULzykVPInKAzvHAnAKGyYmwdOrJM
fAVOQl3tAgMBAAECggEBALLy67kv1yKDNQjGnnLKjk/LW2a7Xs697mrFP9YhDSYh
fjLCWU63Cb4IHazc0l+fcFqNfwfPvLIyNGbNyJOF3/uJjvkfN4sgsFtytbTBAF1Y
hzpFf58R+N1lPx+YLEsJIYjF021uiCBVtU7apzCSAwZOfKHgQOyL1U/AcOE7V0rZ
v7efhQCSDJ76RAY1FuUDw8vk4kevWmWbjeVOoxnMjKfhOwL3Tfm8QXfc3USCv7Xk
85Od8mXxhrxRQLIk1RBYxhUj8uWSK0IvDE/jbyFEZQK10D8LnNWwbk1dg26nE3xu
oQbqUcF05ujlsDFGWCZ40d2mlu0Na/pskyjxu/9GQykCgYEA9lr8kVj+mTNamyPF
/ltc6l/+ofYDaMqZctZdYieZXg3J/6HN7y/xSDS5TBn4TVX7JvSw5rzoY3spzsO/
49ZbCR4bTxM+ZdVZkkLrtNzVonVAiSSLWpK+1oCPOO+1ULIUMmJanJHKkQ5R33iH
2BZaDSC2J11uJc1E+moXnr+YMu8CgYEAzbpUBcB3bmsG14kHh2PEcO03Gm9v7wuF
nPEcrANVuwAxrow/keM+oyKaj3g5EUvlZDMwh6PvlhOo3Xtp5gS+RRfkMVLcQPXd
Apf7B6OEPL54rwrcoZbxEl2+Hf3UUl9SIKastMCdtHzvLmCYh+12eM/R9Lp1D6DL
3sWQRw62DOMCgYEA1o7L5fLyWo9lXDS93hfIRsAwTvKqaXv6RQ/56ODALDAqO5+6
cZT5uX9h2qvLm99Ei9sUrwDcDLhZ4yCNYWtxgfFcq3QBJkO4bTAnhS/ISGOCP286
hznDR6JUGqx657sQ6AjNDgvTtp4YJF8fQM3GxCQ3QPWYVwf+CXKY+8O2VLUCgYEA
i75mtqV/OvTeZ+f/wjrFxEOOK5nIueLktq+dX0bApE7EcKF5yPpIoP2vaYcrlJEu
V7rh2zFDXHksOo5LZ+CO8lYBPnPfgwy/PLTJ4u1ytORZC+Xf6q+iP2yH6M1zvSRc
oCs3o2w3c9NtkN4ynhpyYCwinQ9O1vfNpBwlHe9jQCsCgYB3KRWR4UGc2faQbBE9
fMmbdTkA79gkwvr1q4pRQlCGnOxeIE4vfR4RCkfRkBJimMSI2sNDHFiDQZ8DJq6Y
3cwaL4uUSo9MEdY2ZZxaGgxWaEu4DH+ZV0lJv/RDgTbjD0xwomxXOn/+9UM17Nf9
KYSfdCWcjW0kxJJ7PO4n8d65rQ==
-----END PRIVATE KEY-----
26 changes: 26 additions & 0 deletions pkg/deviceclaimingserver/gateways/testdata/client.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEWzCCAsOgAwIBAgIQNsTUWUKitSTLD+uN4zzpuzANBgkqhkiG9w0BAQsFADCB
hTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMS0wKwYDVQQLDCRqb2hh
bkBKb2hhbi0yLmxvY2FsIChKb2hhbiBTdG9ra2luZykxNDAyBgNVBAMMK21rY2Vy
dCBqb2hhbkBKb2hhbi0yLmxvY2FsIChKb2hhbiBTdG9ra2luZykwHhcNMTkwNjAx
MDAwMDAwWhcNMzAwOTAzMTYyMDU0WjBYMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxv
cG1lbnQgY2VydGlmaWNhdGUxLTArBgNVBAsMJGpvaGFuQEpvaGFuLTIubG9jYWwg
KEpvaGFuIFN0b2traW5nKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AMX6KzdJvFWuN47KigB4l+MAP0bKUwjlnhx8eM+B5N/ZtmV9WebH6rmt2s3oH9xC
jUEQioUdn0HqirEJlSAEGD3JnHXZeNCTiRa8aESe4d8kjdzXzyJl1S3pokchMpoY
aRu7oknNon55SX6lrgaFp7iCw/mo6CynTct1IBlcHJ4/0TWcW70xHWUkJ8jawEug
csQiHekDpg+FG8v9o8F4J0qqdNVx7rVidfFBBUesDzayZ4gIdG/HUpBaS83tjSJw
NIGHvi+xFpo77M+y4dNHkSamao1flVmiyhSs0JAd10C9DAEZm/9QvPKRU8icoDO8
cCcAobJibB06skx8BU5CXe0CAwEAAaNzMHEwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud
JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB8GA1UdIwQY
MBaAFDzAUZ9AtGTILuMWdD2VfCm0D72DMBEGA1UdEQQKMAiCBjAwMDAwMTANBgkq
hkiG9w0BAQsFAAOCAYEAI8mhLKPl4qUlZ2g1vmVrAGTGc0M2dzs4Xp2gyys+puup
sP4pRPQnIrEJaZcI2mk/4TTOpyF1tmLGaZ0V/hMzf07I5vB/Kz+jdj0+3AGVixwR
+KehvHVn6njfcZqa3l4Q7pFWyQtb199M1XPwGkQSEzxthU7dKH/447T8HwKp3xoK
hKb3pNd0h0MXgGGhawHFP5AHpI0x05cWT5zLXu5nXnjYt9UKpPCUH6Htcofg33GX
Y3rj3KvUz9WHYw/6LE+LlKjUKLkCG8bq2qaTRSrJQh5qTJRldzqjJ4qa7A7hUYJN
qm+Wb/FIMIA/sdfdMEwGAWhkZJjZlYoGv3LU7QLIkaCWjRsTs1gRw2EVCo0mFJ6x
LRm0UDBIIr30fEkGhSk38EYiX3HbxkCF61HPehhzL4noMkoDAuMq+8gFRVDBHOlv
YiNn1Y22LBsFdoKkbqI3nI62sFvI8lXpKRrL34lndSCevVXOEUOeupDdD1XvHYHQ
0bPVWAqh/KAO8JMDauCa
-----END CERTIFICATE-----
54 changes: 54 additions & 0 deletions pkg/deviceclaimingserver/gateways/ttgc/root_ca.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package ttgc provides functions to use The Things Gateway Controller.
package ttgc

import (
"context"
"crypto/tls"
"crypto/x509"
"net"

"go.thethings.network/lorawan-stack/v3/pkg/errors"
)

var (
errDialGatewayServer = errors.DefineAborted("dial_gateway_server", "dial Gateway Gerver")
errGatewayServerTLS = errors.DefineAborted(
"gateway_server_tls", "establish TLS connection with Gateway Server",
)
)

func (u *Upstream) getRootCA(ctx context.Context, address string) (*x509.Certificate, error) {
d := new(net.Dialer)
netConn, err := d.DialContext(ctx, "tcp", address)
if err != nil {
return nil, errDialGatewayServer.WithCause(err)
}
defer netConn.Close()

tlsConfig, err := u.GetTLSClientConfig(ctx)
if err != nil {
return nil, err
}
tlsConn := tls.Client(netConn, tlsConfig)
if err := tlsConn.HandshakeContext(ctx); err != nil {
return nil, errGatewayServerTLS.WithCause(err)
}

state := tlsConn.ConnectionState()
verifiedChain := state.VerifiedChains[0]
return verifiedChain[len(verifiedChain)-1], nil
}
Loading

0 comments on commit 15ddbd9

Please sign in to comment.