Skip to content

Commit d8b6040

Browse files
committed
Attempt to configure CA for insecure device during onboarding to cloud
It is expected that the insecure device is within the trust network, and the client application is behind the proxy that authorizes access
1 parent c5fc3e6 commit d8b6040

4 files changed

Lines changed: 86 additions & 13 deletions

File tree

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ jobs:
5858
id: args
5959
run: |
6060
if ${{ github.ref_type == 'tag' }} ; then
61-
echo "args=release --rm-dist" >> $GITHUB_OUTPUT
61+
echo "args=release --clean" >> $GITHUB_OUTPUT
6262
else
63-
echo "args=release --rm-dist --skip-validate --skip-publish" >> $GITHUB_OUTPUT
63+
echo "args=release --clean --skip=validate --skip=publish" >> $GITHUB_OUTPUT
6464
fi
6565
6666
- name: Run GoReleaser

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ inject-web: $(CLIENT_APPLICATION_BINARY_PATH)
104104
.PHONY: inject-web
105105

106106
build:
107-
UI_FILE=$(UI_FILE) UI_SEPARATOR=$(UI_SEPARATOR) goreleaser build --rm-dist --single-target --skip-validate
107+
UI_FILE=$(UI_FILE) UI_SEPARATOR=$(UI_SEPARATOR) goreleaser build --clean --single-target --skip=validate
108108
.PHONY: build
109109

110110
test: env

service/grpc/onboardDevice.go

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ import (
2828
"github.com/plgd-dev/device/v2/schema"
2929
"github.com/plgd-dev/device/v2/schema/acl"
3030
"github.com/plgd-dev/device/v2/schema/cloud"
31+
"github.com/plgd-dev/device/v2/schema/credential"
3132
"github.com/plgd-dev/device/v2/schema/maintenance"
3233
"github.com/plgd-dev/device/v2/schema/softwareupdate"
3334
"github.com/plgd-dev/kit/v2/security"
34-
"github.com/plgd-dev/kit/v2/strings"
3535
"google.golang.org/grpc/codes"
3636
"google.golang.org/grpc/status"
3737
)
@@ -151,6 +151,38 @@ func onboardSecureDevice(ctx context.Context, dev *device, links schema.Resource
151151
})
152152
}
153153

154+
func insecureAddCredentials(ctx context.Context, cloudID string, dev *device, links schema.ResourceLinks, cert string) error {
155+
links = links.GetResourceLinks(credential.ResourceType)
156+
if len(links) == 0 {
157+
// add credential resource is not supported by device
158+
return nil
159+
}
160+
_, err := security.ParseX509FromPEM([]byte(cert))
161+
if err != nil {
162+
return fmt.Errorf("cannot parse CA for device %v: %w", dev.DeviceID(), err)
163+
}
164+
link := links[0]
165+
link.Endpoints = link.Endpoints.FilterUnsecureEndpoints()
166+
setCaCredential := credential.CredentialUpdateRequest{
167+
Credentials: []credential.Credential{
168+
{
169+
Subject: cloudID,
170+
Type: credential.CredentialType_ASYMMETRIC_SIGNING_WITH_CERTIFICATE,
171+
Usage: credential.CredentialUsage_TRUST_CA,
172+
PublicData: &credential.CredentialPublicData{
173+
DataInternal: cert,
174+
Encoding: credential.CredentialPublicDataEncoding_PEM,
175+
},
176+
},
177+
},
178+
}
179+
err = dev.UpdateResource(ctx, link, setCaCredential, nil, coap.WithDeviceID(dev.DeviceID()))
180+
if err != nil {
181+
return fmt.Errorf("cannot add CA to credential resource %v of device %v: %w", link.Href, dev.DeviceID(), err)
182+
}
183+
return nil
184+
}
185+
154186
func onboardInsecureDevice(ctx context.Context, dev *device, links schema.ResourceLinks, req *pb.OnboardDeviceRequest) error {
155187
switch {
156188
case req.GetAuthorizationProviderName() == "":
@@ -160,18 +192,20 @@ func onboardInsecureDevice(ctx context.Context, dev *device, links schema.Resour
160192
case req.GetCoapGatewayAddress() == "":
161193
return fmt.Errorf("invalid URL")
162194
}
163-
var link schema.ResourceLink
164-
165-
for _, l := range links {
166-
if strings.SliceContains(l.ResourceTypes, cloud.ResourceType) {
167-
link = l
168-
break
169-
}
170-
}
171-
if link.Href == "" {
195+
cloudLinks := links.GetResourceLinks(cloud.ResourceType)
196+
if len(cloudLinks) == 0 {
172197
return fmt.Errorf("could not resolve cloud resource link of device %s", dev.DeviceID())
173198
}
199+
link := cloudLinks[0]
174200
link.Endpoints = link.Endpoints.FilterUnsecureEndpoints()
201+
202+
if len(req.GetCertificateAuthorities()) > 0 {
203+
err := insecureAddCredentials(ctx, req.GetHubId(), dev, links, req.GetCertificateAuthorities())
204+
if err != nil {
205+
return err
206+
}
207+
}
208+
175209
err := dev.UpdateResource(ctx, link, cloud.ConfigurationUpdateRequest{
176210
AuthorizationProvider: req.GetAuthorizationProviderName(),
177211
AuthorizationCode: req.GetAuthorizationCode(),

service/grpc/onboardDevice_internal_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,19 @@ package grpc
1818

1919
import (
2020
"context"
21+
"crypto/ecdsa"
22+
"crypto/elliptic"
23+
"crypto/rand"
2124
"strings"
2225
"testing"
2326
"time"
2427

2528
"github.com/plgd-dev/client-application/pb"
2629
"github.com/plgd-dev/device/v2/client/core"
30+
"github.com/plgd-dev/device/v2/pkg/security/generateCertificate"
2731
"github.com/plgd-dev/device/v2/schema"
2832
"github.com/plgd-dev/device/v2/schema/cloud"
33+
"github.com/plgd-dev/device/v2/schema/credential"
2934
"github.com/stretchr/testify/require"
3035
)
3136

@@ -51,3 +56,37 @@ func TestOnboardInsecureDevice(t *testing.T) {
5156
require.Error(t, err)
5257
require.True(t, strings.Contains(err.Error(), "could not set cloud resource of device"))
5358
}
59+
60+
func TestOnboardInsecureDeviceWithCA(t *testing.T) {
61+
// we don't have a insecure device simulator for this test, so we create a fake device
62+
// and try to onboard it
63+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*8)
64+
defer cancel()
65+
dev := device{Device: &core.Device{}}
66+
links := schema.ResourceLinks{
67+
{
68+
Href: cloud.ResourceURI,
69+
ResourceTypes: []string{cloud.ResourceType},
70+
},
71+
{
72+
Href: credential.ResourceURI,
73+
ResourceTypes: []string{credential.ResourceType},
74+
},
75+
}
76+
77+
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
78+
require.NoError(t, err)
79+
caPEM, err := generateCertificate.GenerateRootCA(generateCertificate.Configuration{}, key)
80+
require.NoError(t, err)
81+
82+
err = onboardInsecureDevice(ctx, &dev, links, &pb.OnboardDeviceRequest{
83+
DeviceId: "devId",
84+
CoapGatewayAddress: "coaps+tcp://localhost:5684",
85+
AuthorizationCode: "authCode",
86+
AuthorizationProviderName: "authProviderName",
87+
HubId: "hubId",
88+
CertificateAuthorities: string(caPEM),
89+
})
90+
require.Error(t, err)
91+
require.True(t, strings.Contains(err.Error(), "cannot add CA to credential resource"))
92+
}

0 commit comments

Comments
 (0)