Skip to content

Commit

Permalink
Attempt to configure CA for insecure device during onboarding to cloud
Browse files Browse the repository at this point in the history
It is expected that the insecure device is within the trust network,
and the client application is behind the proxy that authorizes access
  • Loading branch information
jkralik committed Feb 2, 2024
1 parent c5fc3e6 commit 216f65f
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 13 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ jobs:
id: args
run: |
if ${{ github.ref_type == 'tag' }} ; then
echo "args=release --rm-dist" >> $GITHUB_OUTPUT
echo "args=release --clean" >> $GITHUB_OUTPUT
else
echo "args=release --rm-dist --skip-validate --skip-publish" >> $GITHUB_OUTPUT
echo "args=release --clean --skip=validate --skip=publish" >> $GITHUB_OUTPUT
fi
- name: Run GoReleaser
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ inject-web: $(CLIENT_APPLICATION_BINARY_PATH)
.PHONY: inject-web

build:
UI_FILE=$(UI_FILE) UI_SEPARATOR=$(UI_SEPARATOR) goreleaser build --rm-dist --single-target --skip-validate
UI_FILE=$(UI_FILE) UI_SEPARATOR=$(UI_SEPARATOR) goreleaser build --clean --single-target --skip=validate
.PHONY: build

test: env
Expand Down
54 changes: 44 additions & 10 deletions service/grpc/onboardDevice.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ import (
"github.com/plgd-dev/device/v2/schema"
"github.com/plgd-dev/device/v2/schema/acl"
"github.com/plgd-dev/device/v2/schema/cloud"
"github.com/plgd-dev/device/v2/schema/credential"
"github.com/plgd-dev/device/v2/schema/maintenance"
"github.com/plgd-dev/device/v2/schema/softwareupdate"
"github.com/plgd-dev/kit/v2/security"
"github.com/plgd-dev/kit/v2/strings"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand Down Expand Up @@ -151,6 +151,38 @@ func onboardSecureDevice(ctx context.Context, dev *device, links schema.Resource
})
}

func insecureAddCredentials(ctx context.Context, cloudID string, dev *device, links schema.ResourceLinks, cert string) error {
links = links.GetResourceLinks(credential.ResourceType)
if len(links) == 0 {
// add credential resource is not supported by device
return nil
}
_, err := security.ParseX509FromPEM([]byte(cert))
if err != nil {
return fmt.Errorf("cannot parse CA for device %v: %w", dev.DeviceID(), err)
}
link := links[0]
link.Endpoints = link.Endpoints.FilterUnsecureEndpoints()
setCaCredential := credential.CredentialUpdateRequest{
Credentials: []credential.Credential{
{
Subject: cloudID,
Type: credential.CredentialType_ASYMMETRIC_SIGNING_WITH_CERTIFICATE,
Usage: credential.CredentialUsage_TRUST_CA,
PublicData: &credential.CredentialPublicData{
DataInternal: cert,
Encoding: credential.CredentialPublicDataEncoding_PEM,
},
},
},
}
err = dev.UpdateResource(ctx, link, setCaCredential, nil, coap.WithDeviceID(dev.DeviceID()))
if err != nil {
return fmt.Errorf("cannot add CA to credential resource %v of device %v: %w", link.Href, dev.DeviceID(), err)
}
return nil
}

func onboardInsecureDevice(ctx context.Context, dev *device, links schema.ResourceLinks, req *pb.OnboardDeviceRequest) error {
switch {
case req.GetAuthorizationProviderName() == "":
Expand All @@ -160,18 +192,20 @@ func onboardInsecureDevice(ctx context.Context, dev *device, links schema.Resour
case req.GetCoapGatewayAddress() == "":
return fmt.Errorf("invalid URL")
}
var link schema.ResourceLink

for _, l := range links {
if strings.SliceContains(l.ResourceTypes, cloud.ResourceType) {
link = l
break
}
}
if link.Href == "" {
cloudLinks := links.GetResourceLinks(cloud.ResourceType)
if len(cloudLinks) == 0 {
return fmt.Errorf("could not resolve cloud resource link of device %s", dev.DeviceID())
}
link := cloudLinks[0]
link.Endpoints = link.Endpoints.FilterUnsecureEndpoints()

if len(req.GetCertificateAuthorities()) > 0 {
err := insecureAddCredentials(ctx, req.GetHubId(), dev, links, req.GetCertificateAuthorities())
if err != nil {
return err
}
}

err := dev.UpdateResource(ctx, link, cloud.ConfigurationUpdateRequest{
AuthorizationProvider: req.GetAuthorizationProviderName(),
AuthorizationCode: req.GetAuthorizationCode(),
Expand Down
39 changes: 39 additions & 0 deletions service/grpc/onboardDevice_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@ package grpc

import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"strings"
"testing"
"time"

"github.com/plgd-dev/client-application/pb"
"github.com/plgd-dev/device/v2/client/core"
"github.com/plgd-dev/device/v2/pkg/security/generateCertificate"
"github.com/plgd-dev/device/v2/schema"
"github.com/plgd-dev/device/v2/schema/cloud"
"github.com/plgd-dev/device/v2/schema/credential"
"github.com/stretchr/testify/require"
)

Expand All @@ -51,3 +56,37 @@ func TestOnboardInsecureDevice(t *testing.T) {
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "could not set cloud resource of device"))
}

func TestOnboardInsecureDeviceWithCA(t *testing.T) {
// we don't have a insecure device simulator for this test, so we create a fake device
// and try to onboard it
ctx, cancel := context.WithTimeout(context.Background(), time.Second*8)
defer cancel()
dev := device{Device: &core.Device{}}
links := schema.ResourceLinks{
{
Href: cloud.ResourceURI,
ResourceTypes: []string{cloud.ResourceType},
},
{
Href: credential.ResourceURI,
ResourceTypes: []string{credential.ResourceType},
},
}

key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
caPEM, err := generateCertificate.GenerateRootCA(generateCertificate.Configuration{}, key)
require.NoError(t, err)

err = onboardInsecureDevice(ctx, &dev, links, &pb.OnboardDeviceRequest{
DeviceId: "devId",
CoapGatewayAddress: "coaps+tcp://localhost:5684",
AuthorizationCode: "authCode",
AuthorizationProviderName: "authProviderName",
HubId: "hubId",
CertificateAuthorities: string(caPEM),
})
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "cannot add CA to credential resource"))
}

0 comments on commit 216f65f

Please sign in to comment.