Skip to content

Commit

Permalink
Configurable CRL
Browse files Browse the repository at this point in the history
  • Loading branch information
Danielius1922 committed Oct 1, 2024
1 parent 2f351e9 commit 7cb304c
Show file tree
Hide file tree
Showing 18 changed files with 453 additions and 55 deletions.
4 changes: 4 additions & 0 deletions certificate-authority/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,7 @@ signer:
certFile: "/secrets/public/intermediateca.crt"
validFrom: "now-1h"
expiresIn: "87600h"
crl:
enabled: true
externalAddress: "https://0.0.0.0:9101"
expiresIn: "10m"
189 changes: 189 additions & 0 deletions certificate-authority/pb/signingRecords_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package pb_test

import (
"testing"

"github.com/google/uuid"
"github.com/plgd-dev/hub/v2/certificate-authority/pb"
"github.com/stretchr/testify/require"
)

func TestCredentialStatusValidate(t *testing.T) {
tests := []struct {
name string
input *pb.CredentialStatus
wantErr bool
}{
{
name: "Valid credential",
input: &pb.CredentialStatus{
Date: 1659462400000000000,
ValidUntilDate: 1669462400000000000,
CertificatePem: "valid-cert",
Serial: "1234567890",
IssuerId: uuid.New().String(),
},
wantErr: false,
},
{
name: "Missing signing credential date",
input: &pb.CredentialStatus{
Date: 0,
ValidUntilDate: 1669462400000000000,
CertificatePem: "valid-cert",
Serial: "1234567890",
IssuerId: uuid.New().String(),
},
wantErr: true,
},
{
name: "Missing signing credential expiration date",
input: &pb.CredentialStatus{
Date: 1659462400000000000,
ValidUntilDate: 0,
CertificatePem: "valid-cert",
Serial: "1234567890",
IssuerId: uuid.New().String(),
},
wantErr: true,
},
{
name: "Missing signing record credential certificate",
input: &pb.CredentialStatus{
Date: 1659462400000000000,
ValidUntilDate: 1669462400000000000,
CertificatePem: "",
Serial: "1234567890",
IssuerId: uuid.New().String(),
},
wantErr: true,
},
{
name: "Invalid certificate serial number",
input: &pb.CredentialStatus{
Date: 1659462400000000000,
ValidUntilDate: 1669462400000000000,
CertificatePem: "valid-cert",
Serial: "invalid-serial",
IssuerId: uuid.New().String(),
},
wantErr: true,
},
{
name: "Invalid issuer ID",
input: &pb.CredentialStatus{
Date: 1659462400000000000,
ValidUntilDate: 1669462400000000000,
CertificatePem: "valid-cert",
Serial: "1234567890",
IssuerId: "invalid-uuid",
},
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.input.Validate()
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
})
}
}

func TestSigningRecordValidate(t *testing.T) {
validCredential := &pb.CredentialStatus{
Date: 1659462400000000000,
ValidUntilDate: 1669462400000000000,
CertificatePem: "valid-cert",
Serial: "1234567890",
IssuerId: uuid.New().String(),
}

tests := []struct {
name string
input *pb.SigningRecord
wantErr bool
}{
{
name: "Valid signing record",
input: &pb.SigningRecord{
Id: uuid.New().String(),
Owner: "owner",
CommonName: "common_name",
DeviceId: uuid.New().String(),
Credential: validCredential,
},
wantErr: false,
},
{
name: "Missing signing record ID",
input: &pb.SigningRecord{
Id: "",
Owner: "owner",
CommonName: "common_name",
DeviceId: uuid.New().String(),
Credential: validCredential,
},
wantErr: true,
},
{
name: "Invalid signing record ID",
input: &pb.SigningRecord{
Id: "invalid-uuid",
Owner: "owner",
CommonName: "common_name",
DeviceId: uuid.New().String(),
Credential: validCredential,
},
wantErr: true,
},
{
name: "Invalid device ID",
input: &pb.SigningRecord{
Id: uuid.New().String(),
Owner: "owner",
CommonName: "common_name",
DeviceId: "invalid-uuid",
Credential: validCredential,
},
wantErr: true,
},
{
name: "Missing common name",
input: &pb.SigningRecord{
Id: uuid.New().String(),
Owner: "owner",
CommonName: "",
DeviceId: uuid.New().String(),
Credential: validCredential,
},
wantErr: true,
},
{
name: "Missing owner",
input: &pb.SigningRecord{
Id: uuid.New().String(),
Owner: "",
CommonName: "common_name",
DeviceId: uuid.New().String(),
Credential: validCredential,
},
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.input.Validate()
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
})
}
}
2 changes: 1 addition & 1 deletion certificate-authority/service/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (c *Config) Validate() error {
return fmt.Errorf("hubID('%v') - %w", c.HubID, err)
}

_, err := grpcService.NewSigner(c.APIs.GRPC.Authorization.OwnerClaim, c.APIs.HTTP.Addr, c.HubID, c.Signer)
_, err := grpcService.NewSigner(c.APIs.GRPC.Authorization.OwnerClaim, c.HubID, c.Signer)
if err != nil {
return fmt.Errorf("signer('%v') - %w", c.Signer, err)
}
Expand Down
28 changes: 25 additions & 3 deletions certificate-authority/service/grpc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,32 @@ import (

type Config = server.Config

type CRLConfig struct {
Enabled bool `yaml:"enabled" json:"enabled" `
ExternalAddress string `yaml:"externalAddress" json:"externalAddress" `
ExpiresIn time.Duration `yaml:"expiresIn" json:"expiresIn"`
}

func (c *CRLConfig) Validate() error {
if !c.Enabled {
return nil
}
if c.ExternalAddress == "" {
return fmt.Errorf("externalAddress('%v')", c.ExternalAddress)
}
if c.ExpiresIn <= time.Minute {
return fmt.Errorf("expiresIn('%v') - less than %v", c.ExpiresIn, time.Minute)
}
return nil
}

type SignerConfig struct {
CAPool interface{} `yaml:"caPool" json:"caPool" description:"file path to the root certificates in PEM format"`
KeyFile urischeme.URIScheme `yaml:"keyFile" json:"keyFile" description:"file name of CA private key in PEM format"`
CertFile urischeme.URIScheme `yaml:"certFile" json:"certFile" description:"file name of CA certificate in PEM format"`
ValidFrom string `yaml:"validFrom" json:"validFrom" description:"format https://github.com/karrick/tparse"`
ExpiresIn time.Duration `yaml:"expiresIn" json:"expiresIn"`
CRL CRLConfig `yaml:"crl" json:"crl"`

caPoolArray []urischeme.URIScheme `yaml:"-" json:"-"`
}
Expand All @@ -36,13 +56,15 @@ func (c *SignerConfig) Validate() error {
return fmt.Errorf("keyFile('%v')", c.KeyFile)
}
if c.ExpiresIn <= 0 {
return fmt.Errorf("expiresIn('%v')", c.KeyFile)
return fmt.Errorf("expiresIn('%v')", c.ExpiresIn)
}
_, err := tparse.ParseNow(time.RFC3339, c.ValidFrom)
if err != nil {
return fmt.Errorf("validFrom('%v')", c.ValidFrom)
return fmt.Errorf("validFrom('%v').%w", c.ValidFrom, err)
}
if err := c.CRL.Validate(); err != nil {
return fmt.Errorf("crl.%w", err)
}

return nil
}

Expand Down
29 changes: 22 additions & 7 deletions certificate-authority/service/grpc/deleteSigningRecords_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import (
func TestCertificateAuthorityServerDeleteSigningRecords(t *testing.T) {
owner := events.OwnerToUUID("owner")
const ownerClaim = "sub"
token := config.CreateJwtToken(t, jwt.MapClaims{
ownerClaim: owner,
})
ctx := pkgGrpc.CtxWithToken(context.Background(), token)
r := &store.SigningRecord{
Id: "9d017fad-2961-4fcc-94a9-1e1291a88ffc",
Owner: owner,
Expand All @@ -38,18 +42,28 @@ func TestCertificateAuthorityServerDeleteSigningRecords(t *testing.T) {
}
type args struct {
req *pb.DeleteSigningRecordsRequest
ctx context.Context
}
tests := []struct {
name string
args args
want int64
name string
args args
want int64
wantErr bool
}{
{
name: "missing token with ownerClaim in ctx",
args: args{
ctx: context.Background(),
},
wantErr: true,
},
{
name: "invalidID",
args: args{
req: &pb.DeleteSigningRecordsRequest{
IdFilter: []string{"invalidID"},
},
ctx: ctx,
},
},
{
Expand All @@ -58,6 +72,7 @@ func TestCertificateAuthorityServerDeleteSigningRecords(t *testing.T) {
req: &pb.DeleteSigningRecordsRequest{
IdFilter: []string{r.GetId()},
},
ctx: ctx,
},
want: 1,
},
Expand Down Expand Up @@ -85,14 +100,14 @@ func TestCertificateAuthorityServerDeleteSigningRecords(t *testing.T) {

pb.RegisterCertificateAuthorityServer(ch, ca)
grpcClient := pb.NewCertificateAuthorityClient(ch)
token := config.CreateJwtToken(t, jwt.MapClaims{
ownerClaim: owner,
})
ctx := pkgGrpc.CtxWithToken(context.Background(), token)

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := grpcClient.DeleteSigningRecords(ctx, tt.args.req)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tt.want, got.GetCount())
})
Expand Down
2 changes: 1 addition & 1 deletion certificate-authority/service/grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func (s *CertificateAuthorityServer) Close() {
}

func (s *CertificateAuthorityServer) load() (bool, error) {
signer, err := NewSigner(s.ownerClaim, s.hubID, s.crlServerAddress, s.signerConfig)
signer, err := NewSigner(s.ownerClaim, s.hubID, s.signerConfig)
if err != nil {
return false, fmt.Errorf("cannot create signer: %w", err)
}
Expand Down
Loading

0 comments on commit 7cb304c

Please sign in to comment.