From 8a73731c0d119c8d99a88202a74aa5b747160a94 Mon Sep 17 00:00:00 2001 From: Jozef Kralik Date: Wed, 31 Jan 2024 16:33:27 +0000 Subject: [PATCH] add credential resource to allow configure CA during onboard bridge the device --- bridge/device/cloud/manager.go | 29 ++-- bridge/device/config.go | 7 + bridge/device/credential/config.go | 23 +++ bridge/device/credential/manager.go | 141 ++++++++++++++++++ bridge/device/device.go | 27 +++- bridge/net/network.go | 25 +++- bridge/resources/cloud/resource.go | 2 +- .../resources/secure/credential/resource.go | 44 ++++++ cmd/ocfbridge/config.yaml | 4 +- cmd/ocfbridge/main.go | 3 + schema/credential/credential.go | 46 +++--- schema/link.go | 10 +- schema/link_test.go | 2 +- test/coap-gateway/service/refreshToken.go | 2 +- .../coap-gateway/service/resourceDirectory.go | 2 +- test/coap-gateway/service/signIn.go | 2 +- test/coap-gateway/service/signUp.go | 2 +- 17 files changed, 312 insertions(+), 59 deletions(-) create mode 100644 bridge/device/credential/config.go create mode 100644 bridge/device/credential/manager.go create mode 100644 bridge/resources/secure/credential/resource.go diff --git a/bridge/device/cloud/manager.go b/bridge/device/cloud/manager.go index 444bfd25..bb3a3394 100644 --- a/bridge/device/cloud/manager.go +++ b/bridge/device/cloud/manager.go @@ -24,7 +24,7 @@ import ( "crypto/x509" "fmt" "log" - goSync "sync" + "sync" "time" "github.com/google/uuid" @@ -73,7 +73,7 @@ type Manager struct { getCertificates func(deviceID string) []tls.Certificate private struct { - mutex goSync.Mutex + mutex sync.Mutex cfg Configuration } @@ -351,26 +351,21 @@ func (c *Manager) dial(ctx context.Context) error { _ = c.close() cfg := c.getCloudConfiguration() - var verifyPeer func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error - var rootCAs *x509.CertPool cas := c.getCAPool() - if (len(cas)) > 0 { - rootCAs = x509.NewCertPool() - for _, ca := range cas { - rootCAs.AddCert(ca) - } - verifyPeer = coap.NewVerifyPeerCertificate(rootCAs, func(cert *x509.Certificate) error { - cloudID, err := uuid.Parse(c.getCloudConfiguration().CloudID) - if err != nil { - return fmt.Errorf("cannot parse cloudID: %w", err) - } - return coap.VerifyCloudCertificate(cert, cloudID) - }) + rootCAs := x509.NewCertPool() + for _, ca := range cas { + rootCAs.AddCert(ca) } + verifyPeer := coap.NewVerifyPeerCertificate(rootCAs, func(cert *x509.Certificate) error { + cloudID, err := uuid.Parse(c.getCloudConfiguration().CloudID) + if err != nil { + return fmt.Errorf("cannot parse cloudID: %w", err) + } + return coap.VerifyCloudCertificate(cert, cloudID) + }) tlsConfig := &tls.Config{ InsecureSkipVerify: true, //nolint:gosec - RootCAs: rootCAs, Certificates: c.getCertificates(c.deviceID.String()), VerifyPeerCertificate: verifyPeer, } diff --git a/bridge/device/config.go b/bridge/device/config.go index 8d63bfef..c8fad9ce 100644 --- a/bridge/device/config.go +++ b/bridge/device/config.go @@ -23,6 +23,7 @@ import ( "github.com/google/uuid" "github.com/plgd-dev/device/v2/bridge/device/cloud" + "github.com/plgd-dev/device/v2/bridge/device/credential" ) type CloudConfig struct { @@ -30,6 +31,11 @@ type CloudConfig struct { cloud.Config } +type CredentialConfig struct { + Enabled bool + credential.Config +} + type Config struct { ID uuid.UUID Name string @@ -37,6 +43,7 @@ type Config struct { ResourceTypes []string MaxMessageSize uint32 Cloud CloudConfig + Credential CredentialConfig } func (cfg *Config) Validate() error { diff --git a/bridge/device/credential/config.go b/bridge/device/credential/config.go new file mode 100644 index 00000000..486b5920 --- /dev/null +++ b/bridge/device/credential/config.go @@ -0,0 +1,23 @@ +/**************************************************************************** + * + * Copyright (c) 2024 plgd.dev s.r.o. + * + * 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 credential + +import "github.com/plgd-dev/device/v2/schema/credential" + +type Config = credential.CredentialResponse diff --git a/bridge/device/credential/manager.go b/bridge/device/credential/manager.go new file mode 100644 index 00000000..3c0a7d42 --- /dev/null +++ b/bridge/device/credential/manager.go @@ -0,0 +1,141 @@ +/**************************************************************************** + * + * Copyright (c) 2024 plgd.dev s.r.o. + * + * 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 credential + +import ( + "crypto/x509" + + "github.com/plgd-dev/device/v2/bridge/net" + "github.com/plgd-dev/device/v2/bridge/resources" + "github.com/plgd-dev/device/v2/pkg/codec/cbor" + "github.com/plgd-dev/device/v2/schema/credential" + "github.com/plgd-dev/device/v2/schema/interfaces" + "github.com/plgd-dev/go-coap/v3/message/codes" + "github.com/plgd-dev/go-coap/v3/message/pool" + coapSync "github.com/plgd-dev/go-coap/v3/pkg/sync" + "github.com/plgd-dev/kit/v2/security" +) + +type Manager struct { + credentials *coapSync.Map[int, credential.Credential] + save func() +} + +func New(save func()) *Manager { + if save == nil { + save = func() {} + } + return &Manager{ + save: save, + credentials: coapSync.NewMap[int, credential.Credential](), + } +} + +func (m *Manager) GetCAPool() []*x509.Certificate { + certs := make([]*x509.Certificate, 0, m.credentials.Length()) + m.credentials.Range(func(key int, value credential.Credential) bool { + if value.Type != credential.CredentialType_ASYMMETRIC_SIGNING_WITH_CERTIFICATE { + return true + } + if value.Usage != credential.CredentialUsage_TRUST_CA && value.Usage != credential.CredentialUsage_MFG_TRUST_CA { + return true + } + cas, err := security.ParseX509FromPEM(value.PublicData.Data()) + if err != nil { + return true + } + certs = append(certs, cas...) + return true + }) + return certs +} + +func (m *Manager) getNextID() int { + var id int + m.credentials.Range(func(key int, value credential.Credential) bool { + if key > id { + id = key + } + return true + }) + return id + 1 +} + +func (m *Manager) AddOrReplaceCredential(c credential.Credential) { + if c.Type == credential.CredentialType_EMPTY { + return + } + for { + _, loaded := m.credentials.LoadOrStore(c.ID, c) + if !loaded { + return + } + c.ID = m.getNextID() + } +} + +func (m *Manager) AddOrReplaceCredentials(ca ...credential.Credential) { + for _, c := range ca { + m.AddOrReplaceCredential(c) + } +} + +func (m *Manager) RemoveRootCAs(ids ...int) { + for _, id := range ids { + m.credentials.Delete(id) + } +} + +func (m *Manager) ClearRootCAs() { + _ = m.credentials.LoadAndDeleteAll() +} + +func (m *Manager) getRep() credential.CredentialResponse { + cas := m.credentials.CopyData() + creds := credential.CredentialResponse{ + Interfaces: []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_RW}, + ResourceTypes: []string{credential.ResourceType}, + Credentials: make([]credential.Credential, 0, len(cas)), + } + for _, cred := range cas { + creds.Credentials = append(creds.Credentials, cred) + } + return creds +} + +func (m *Manager) Get(request *net.Request) (*pool.Message, error) { + creds := m.getRep() + return resources.CreateResponseContent(request.Context(), creds, codes.Content) +} + +func (m *Manager) Post(request *net.Request) (*pool.Message, error) { + var cfg credential.CredentialUpdateRequest + err := cbor.ReadFrom(request.Body(), &cfg) + if err != nil { + return resources.CreateResponseBadRequest(request.Context(), err) + } + m.AddOrReplaceCredentials(cfg.Credentials...) + m.save() + creds := m.getRep() + return resources.CreateResponseContent(request.Context(), creds, codes.Changed) +} + +func (m *Manager) ExportConfig() Config { + return m.getRep() +} diff --git a/bridge/device/device.go b/bridge/device/device.go index c72cd0b5..18dbf361 100644 --- a/bridge/device/device.go +++ b/bridge/device/device.go @@ -21,18 +21,22 @@ package device import ( "bytes" "context" + "crypto/x509" "fmt" "github.com/google/uuid" "github.com/plgd-dev/device/v2/bridge/device/cloud" + "github.com/plgd-dev/device/v2/bridge/device/credential" "github.com/plgd-dev/device/v2/bridge/net" "github.com/plgd-dev/device/v2/bridge/resources" cloudResource "github.com/plgd-dev/device/v2/bridge/resources/cloud" resourcesDevice "github.com/plgd-dev/device/v2/bridge/resources/device" "github.com/plgd-dev/device/v2/bridge/resources/discovery" "github.com/plgd-dev/device/v2/bridge/resources/maintenance" + credentialResource "github.com/plgd-dev/device/v2/bridge/resources/secure/credential" "github.com/plgd-dev/device/v2/schema" cloudSchema "github.com/plgd-dev/device/v2/schema/cloud" + credentialSchema "github.com/plgd-dev/device/v2/schema/credential" plgdDevice "github.com/plgd-dev/device/v2/schema/device" maintenanceSchema "github.com/plgd-dev/device/v2/schema/maintenance" plgdResources "github.com/plgd-dev/device/v2/schema/resources" @@ -58,6 +62,7 @@ type Device struct { cfg Config resources *sync.Map[string, Resource] cloudManager *cloud.Manager + credential *credential.Manager onDeviceUpdated func(d *Device) } @@ -81,6 +86,13 @@ func (d *Device) ExportConfig() Config { cfg := d.cfg if d.cloudManager != nil { cfg.Cloud.Config = d.cloudManager.ExportConfig() + } else { + cfg.Cloud.Enabled = false + } + if d.credential != nil { + cfg.Credential.Config = d.credential.ExportConfig() + } else { + cfg.Credential.Enabled = false } return cfg } @@ -146,7 +158,20 @@ func New(cfg Config, opts ...Option) *Device { d.AddResource(maintenance.New(maintenanceSchema.ResourceURI, func() { d.UnregisterFromCloud() })) - + if cfg.Credential.Enabled { + d.credential = credential.New(func() { + d.onDeviceUpdated(d) + }) + d.AddResource(credentialResource.New(credentialSchema.ResourceURI, d.credential)) + origGetCAPool := o.getCAPool + o.getCAPool = func() []*x509.Certificate { + cas := d.credential.GetCAPool() + if origGetCAPool != nil { + return append(cas, origGetCAPool()...) + } + return cas + } + } if cfg.Cloud.Enabled { opts := []cloud.Option{cloud.WithMaxMessageSize(cfg.MaxMessageSize)} if o.getCAPool != nil { diff --git a/bridge/net/network.go b/bridge/net/network.go index a370a078..3c70cd01 100644 --- a/bridge/net/network.go +++ b/bridge/net/network.go @@ -366,16 +366,31 @@ func New(cfg Config, handler RequestHandler) (*Net, error) { return n, nil } +func (n *Net) getNetwork(cm *net.ControlMessage, localHost, localPort string) string { + if cm != nil { + if cm.Dst.To4() == nil { + return UDP6 + } + return UDP4 + } + p := n.cfg.externalAddressesPort.filterByPort(localPort) + if len(p) == 1 { + return p[0].network + } + ip := gonet.ParseIP(localHost) + if ip.To4() == nil { + return UDP6 + } + return UDP4 +} + func (n *Net) GetEndpoints(cm *net.ControlMessage, localAddr string) schema.Endpoints { - _, localPort, err := gonet.SplitHostPort(localAddr) + localHost, localPort, err := gonet.SplitHostPort(localAddr) if err != nil { log.Printf("cannot get local address: %v", err) return nil } - network := UDP4 - if cm.Dst.To4() == nil { - network = UDP6 - } + network := n.getNetwork(cm, localHost, localPort) filteredByNetwork := n.cfg.externalAddressesPort.filterByNetwork(network) filtered := filteredByNetwork.filterByPort(localPort) if len(filtered) == 0 { diff --git a/bridge/resources/cloud/resource.go b/bridge/resources/cloud/resource.go index fdc074b8..f5df1c4e 100644 --- a/bridge/resources/cloud/resource.go +++ b/bridge/resources/cloud/resource.go @@ -37,7 +37,7 @@ type Manager interface { func New(uri string, m Manager) *Resource { d := &Resource{} - d.Resource = resources.NewResource(uri, m.Get, m.Post, []string{plgdCloud.ResourceType}, []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_R}) + d.Resource = resources.NewResource(uri, m.Get, m.Post, []string{plgdCloud.ResourceType}, []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_RW}) // don't publish cloud resource to cloud d.PolicyBitMask &= ^resources.PublishToCloud return d diff --git a/bridge/resources/secure/credential/resource.go b/bridge/resources/secure/credential/resource.go new file mode 100644 index 00000000..e453fd92 --- /dev/null +++ b/bridge/resources/secure/credential/resource.go @@ -0,0 +1,44 @@ +/**************************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * 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 credential + +import ( + "github.com/plgd-dev/device/v2/bridge/net" + "github.com/plgd-dev/device/v2/bridge/resources" + "github.com/plgd-dev/device/v2/schema/credential" + "github.com/plgd-dev/device/v2/schema/interfaces" + "github.com/plgd-dev/go-coap/v3/message/pool" +) + +type Resource struct { + *resources.Resource +} + +type Manager interface { + Get(req *net.Request) (*pool.Message, error) + Post(req *net.Request) (*pool.Message, error) +} + +func New(uri string, m Manager) *Resource { + d := &Resource{} + d.Resource = resources.NewResource(uri, m.Get, m.Post, []string{credential.ResourceType}, []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_RW}) + // don't publish cloud resource to cloud + d.PolicyBitMask &= ^resources.PublishToCloud + return d +} diff --git a/cmd/ocfbridge/config.yaml b/cmd/ocfbridge/config.yaml index bb621047..e714443a 100644 --- a/cmd/ocfbridge/config.yaml +++ b/cmd/ocfbridge/config.yaml @@ -6,5 +6,5 @@ apis: - "127.0.0.1:15683" - "[::1]:15683" maxMessageSize: 2097152 -numGeneratedBridgedDevices: 100 -numResourcesPerDevice: 256 +numGeneratedBridgedDevices: 3 +numResourcesPerDevice: 16 diff --git a/cmd/ocfbridge/main.go b/cmd/ocfbridge/main.go index e1dd6c75..e910d7e5 100644 --- a/cmd/ocfbridge/main.go +++ b/cmd/ocfbridge/main.go @@ -162,6 +162,9 @@ func main() { Cloud: device.CloudConfig{ Enabled: true, }, + Credentials: device.CredentialsConfig{ + Enabled: true, + }, }, device.WithGetAdditionalPropertiesForResponse(func() map[string]interface{} { return map[string]interface{}{ "my-property": "my-value", diff --git a/schema/credential/credential.go b/schema/credential/credential.go index 40b09985..c0f8ca75 100644 --- a/schema/credential/credential.go +++ b/schema/credential/credential.go @@ -31,17 +31,17 @@ const ( ) type Credential struct { - ID int `json:"credid,omitempty"` - Type CredentialType `json:"credtype"` - Subject string `json:"subjectuuid"` - Usage CredentialUsage `json:"credusage,omitempty"` - SupportedRefreshMethods []CredentialRefreshMethod `json:"crms,omitempty"` - OptionalData *CredentialOptionalData `json:"optionaldata,omitempty"` - Period string `json:"period,omitempty"` - PrivateData *CredentialPrivateData `json:"privatedata,omitempty"` - PublicData *CredentialPublicData `json:"publicdata,omitempty"` - RoleID *CredentialRoleID `json:"roleid,omitempty"` - Tag string `json:"tag,omitempty"` + ID int `json:"credid,omitempty" yaml:"id,omitempty"` + Type CredentialType `json:"credtype" yaml:"type"` + Subject string `json:"subjectuuid" yaml:"subject"` + Usage CredentialUsage `json:"credusage,omitempty" yaml:"usage,omitempty"` + SupportedRefreshMethods []CredentialRefreshMethod `json:"crms,omitempty" yaml:"supportedRefreshMethods,omitempty"` + OptionalData *CredentialOptionalData `json:"optionaldata,omitempty" yaml:"optionalData,omitempty"` + Period string `json:"period,omitempty" yaml:"period,omitempty"` + PrivateData *CredentialPrivateData `json:"privatedata,omitempty" yaml:"privateData,omitempty"` + PublicData *CredentialPublicData `json:"publicdata,omitempty" yaml:"publicData,omitempty"` + RoleID *CredentialRoleID `json:"roleid,omitempty" yaml:"roleID,omitempty"` + Tag string `json:"tag,omitempty" yaml:"tag,omitempty"` } type CredentialType uint8 @@ -117,9 +117,9 @@ const ( ) type CredentialOptionalData struct { - DataInternal interface{} `json:"data"` - Encoding CredentialOptionalDataEncoding `json:"encoding"` - IsRevoked bool `json:"revstat"` + DataInternal interface{} `json:"data" yaml:"data"` + Encoding CredentialOptionalDataEncoding `json:"encoding" yaml:"encoding"` + IsRevoked bool `json:"revstat" yaml:"isRevoked,omitempty"` } func toByte(v interface{}) []byte { @@ -181,8 +181,8 @@ const ( ) type CredentialPublicData struct { - DataInternal interface{} `json:"data"` - Encoding CredentialPublicDataEncoding `json:"encoding"` + DataInternal interface{} `json:"data" yaml:"data"` + Encoding CredentialPublicDataEncoding `json:"encoding" yaml:"encoding"` } func (c CredentialPublicData) Data() []byte { @@ -202,16 +202,16 @@ const ( ) type CredentialRoleID struct { - Authority string `json:"authority,omitempty"` - Role string `json:"role,omitempty"` + Authority string `json:"authority,omitempty" yaml:"authority,omitempty"` + Role string `json:"role,omitempty" yaml:"role,omitempty"` } type CredentialResponse struct { - ResourceOwner string `json:"rowneruuid"` - Interfaces []string `json:"if"` - ResourceTypes []string `json:"rt"` - Name string `json:"n"` - Credentials []Credential `json:"creds"` + ResourceOwner string `json:"rowneruuid" yaml:"resourceOwner,omitempty"` + Interfaces []string `json:"if,omitempty" yaml:"-"` + ResourceTypes []string `json:"rt,omitempty" yaml:"-"` + Name string `json:"n,omitempty" yaml:"name,omitempty"` + Credentials []Credential `json:"creds" yaml:"creds"` } type CredentialUpdateRequest struct { diff --git a/schema/link.go b/schema/link.go index 131430bc..8100cef3 100644 --- a/schema/link.go +++ b/schema/link.go @@ -50,12 +50,12 @@ type ResourceLinks []ResourceLink // https://openconnectivity.org/specs/OCF_Core_Specification_v2.0.0.pdf type Policy struct { BitMask BitMask `json:"bm"` - UDPPort uint16 `json:"port"` - TCPPort uint16 `json:"x.org.iotivity.tcp"` - TCPTLSPort uint16 `json:"x.org.iotivity.tls"` + UDPPort uint16 `json:"port,omitempty"` + TCPPort uint16 `json:"x.org.iotivity.tcp,omitempty"` + TCPTLSPort uint16 `json:"x.org.iotivity.tls,omitempty"` // Secured is true if the resource is only available via an encrypted connection. - Secured bool `json:"sec"` + Secured *bool `json:"sec,omitempty"` } // Endpoint is defined on the line 2439 and 1892, Priority on 2434 of the Core specification: @@ -243,7 +243,7 @@ func (r ResourceLink) patchEndpoint(addr kitNet.Addr, deviceEndpoints Endpoints) } r.Endpoints = make([]Endpoint, 0, 4) if r.Policy.UDPPort != 0 { - if r.Policy.Secured { + if r.Policy.Secured != nil && *r.Policy.Secured { r.Endpoints = append(r.Endpoints, udpTlsEndpoint(addr.SetPort(r.Policy.UDPPort))) } else { r.Endpoints = append(r.Endpoints, udpEndpoint(addr.SetPort(r.Policy.UDPPort))) diff --git a/schema/link_test.go b/schema/link_test.go index 54c4f371..208b67cb 100644 --- a/schema/link_test.go +++ b/schema/link_test.go @@ -272,7 +272,7 @@ func TestResourceLinkPatchEndpoint(t *testing.T) { UDPPort: 5683, TCPPort: 5683, TCPTLSPort: 5684, - Secured: tt.args.secured, + Secured: &tt.args.secured, }, } got := r.PatchEndpoint(tt.args.addr, nil) diff --git a/test/coap-gateway/service/refreshToken.go b/test/coap-gateway/service/refreshToken.go index 18d054f5..694a392f 100644 --- a/test/coap-gateway/service/refreshToken.go +++ b/test/coap-gateway/service/refreshToken.go @@ -3,10 +3,10 @@ package service import ( "fmt" + "github.com/plgd-dev/device/v2/pkg/codec/cbor" "github.com/plgd-dev/device/v2/pkg/ocf/cloud" coapCodes "github.com/plgd-dev/go-coap/v3/message/codes" "github.com/plgd-dev/go-coap/v3/mux" - "github.com/plgd-dev/kit/v2/codec/cbor" ) func refreshTokenPostHandler(req *mux.Message, client *Client) { diff --git a/test/coap-gateway/service/resourceDirectory.go b/test/coap-gateway/service/resourceDirectory.go index 0e668c67..8fd61ca3 100644 --- a/test/coap-gateway/service/resourceDirectory.go +++ b/test/coap-gateway/service/resourceDirectory.go @@ -25,10 +25,10 @@ import ( "strconv" "strings" + "github.com/plgd-dev/device/v2/pkg/codec/cbor" "github.com/plgd-dev/device/v2/pkg/ocf/cloud" coapCodes "github.com/plgd-dev/go-coap/v3/message/codes" "github.com/plgd-dev/go-coap/v3/mux" - "github.com/plgd-dev/kit/v2/codec/cbor" ) // fixHref ensures that href starts with "/" and does not end with "/". diff --git a/test/coap-gateway/service/signIn.go b/test/coap-gateway/service/signIn.go index 3ec9b23b..f1a4e532 100644 --- a/test/coap-gateway/service/signIn.go +++ b/test/coap-gateway/service/signIn.go @@ -21,10 +21,10 @@ package service import ( "fmt" + "github.com/plgd-dev/device/v2/pkg/codec/cbor" "github.com/plgd-dev/device/v2/pkg/ocf/cloud" coapCodes "github.com/plgd-dev/go-coap/v3/message/codes" "github.com/plgd-dev/go-coap/v3/mux" - "github.com/plgd-dev/kit/v2/codec/cbor" ) // https://github.com/openconnectivityfoundation/security/blob/master/swagger2.0/oic.sec.session.swagger.json diff --git a/test/coap-gateway/service/signUp.go b/test/coap-gateway/service/signUp.go index be7509eb..ee7df5ff 100644 --- a/test/coap-gateway/service/signUp.go +++ b/test/coap-gateway/service/signUp.go @@ -21,10 +21,10 @@ package service import ( "fmt" + "github.com/plgd-dev/device/v2/pkg/codec/cbor" "github.com/plgd-dev/device/v2/pkg/ocf/cloud" coapCodes "github.com/plgd-dev/go-coap/v3/message/codes" "github.com/plgd-dev/go-coap/v3/mux" - "github.com/plgd-dev/kit/v2/codec/cbor" ) // https://github.com/openconnectivityfoundation/security/blob/master/swagger2.0/oic.sec.account.swagger.json