Skip to content

Commit

Permalink
fixup! Configurable CRL
Browse files Browse the repository at this point in the history
  • Loading branch information
Danielius1922 committed Oct 2, 2024
1 parent 7cb304c commit 1be10f8
Show file tree
Hide file tree
Showing 24 changed files with 428 additions and 241 deletions.
3 changes: 1 addition & 2 deletions certificate-authority/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ apis:
tokenTrustVerification:
cacheExpiration: 30s
http:
externalAddress: "https://0.0.0.0:9101"
address: "0.0.0.0:9101"
readTimeout: 8s
readHeaderTimeout: 4s
Expand Down Expand Up @@ -112,6 +113,4 @@ signer:
validFrom: "now-1h"
expiresIn: "87600h"
crl:
enabled: true
externalAddress: "https://0.0.0.0:9101"
expiresIn: "10m"
11 changes: 8 additions & 3 deletions certificate-authority/service/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package service
import (
"fmt"
"net"
"net/url"
"time"

"github.com/go-co-op/gocron/v2"
Expand Down Expand Up @@ -40,7 +41,7 @@ func (c *Config) Validate() error {
return fmt.Errorf("hubID('%v') - %w", c.HubID, err)
}

_, err := grpcService.NewSigner(c.APIs.GRPC.Authorization.OwnerClaim, c.HubID, c.Signer)
_, err := grpcService.NewSigner(c.APIs.GRPC.Authorization.OwnerClaim, c.HubID, c.APIs.HTTP.ExternalAddress, c.Signer)
if err != nil {
return fmt.Errorf("signer('%v') - %w", c.Signer, err)
}
Expand All @@ -65,11 +66,15 @@ func (c *APIsConfig) Validate() error {
}

type HTTPConfig struct {
Addr string `yaml:"address" json:"address"`
Server httpServer.Config `yaml:",inline" json:",inline"`
ExternalAddress string `yaml:"externalAddress" json:"externalAddress"`
Addr string `yaml:"address" json:"address"`
Server httpServer.Config `yaml:",inline" json:",inline"`
}

func (c *HTTPConfig) Validate() error {
if _, err := url.ParseRequestURI(c.ExternalAddress); err != nil {
return fmt.Errorf("externalAddress('%v') invalid", c.ExternalAddress)
}
if _, err := net.ResolveTCPAddr("tcp", c.Addr); err != nil {
return fmt.Errorf("address('%v') - %w", c.Addr, err)
}
Expand Down
51 changes: 51 additions & 0 deletions certificate-authority/service/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,57 @@ func TestConfigValidate(t *testing.T) {
}
}

func TestHTTPConfigValidate(t *testing.T) {
type args struct {
cfg service.HTTPConfig
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "valid",
args: args{
cfg: test.MakeHTTPConfig(),
},
},
{
name: "invalid external address",
args: args{
cfg: func() service.HTTPConfig {
cfg := test.MakeHTTPConfig()
cfg.ExternalAddress = "invalid"
return cfg
}(),
},
wantErr: true,
},
{
name: "invalid address",
args: args{
cfg: func() service.HTTPConfig {
cfg := test.MakeHTTPConfig()
cfg.Addr = "invalid"
return cfg
}(),
},
wantErr: true,
},
}

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

func TestStorageConfigValidate(t *testing.T) {
type args struct {
cfg service.StorageConfig
Expand Down
11 changes: 5 additions & 6 deletions certificate-authority/service/grpc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@ 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"`
ExpiresIn time.Duration `yaml:"expiresIn" json:"expiresIn"`

// needed by tests with cqldb - remove once support for CRL
// is implemented in cqldb or cqldb is removed
Enabled bool `yaml:"-" json:"-"`
}

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)
}
Expand Down
158 changes: 158 additions & 0 deletions certificate-authority/service/grpc/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package grpc_test

import (
"testing"
"time"

"github.com/plgd-dev/hub/v2/certificate-authority/service/grpc"
"github.com/plgd-dev/hub/v2/pkg/config/property/urischeme"
"github.com/stretchr/testify/require"
)

func TestCRLConfigValidate(t *testing.T) {
tests := []struct {
name string
input grpc.CRLConfig
wantErr bool
}{
{
name: "Disabled CRLConfig",
input: grpc.CRLConfig{
Enabled: false,
},
},
{
name: "Enabled CRLConfig with valid ExternalAddress and ExpiresIn",
input: grpc.CRLConfig{
Enabled: true,
ExpiresIn: time.Hour,
},
},
{
name: "Enabled CRLConfig with ExpiresIn less than 1 minute",
input: grpc.CRLConfig{
Enabled: true,
ExpiresIn: 30 * time.Second,
},
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 TestSignerConfigValidate(t *testing.T) {
crl := grpc.CRLConfig{
Enabled: true,
ExpiresIn: time.Hour,
}
tests := []struct {
name string
input grpc.SignerConfig
wantErr bool
}{
{
name: "Valid SignerConfig",
input: grpc.SignerConfig{
CAPool: []string{"ca1.pem", "ca2.pem"},
KeyFile: urischeme.URIScheme("key.pem"),
CertFile: urischeme.URIScheme("cert.pem"),
ValidFrom: time.Now().Format(time.RFC3339),
ExpiresIn: time.Hour * 24,
CRL: crl,
},
},
{
name: "Invalid CA Pool",
input: grpc.SignerConfig{
CAPool: 42,
KeyFile: urischeme.URIScheme("key.pem"),
CertFile: urischeme.URIScheme("cert.pem"),
ValidFrom: time.Now().Format(time.RFC3339),
ExpiresIn: time.Hour * 24,
CRL: crl,
},
wantErr: true,
},
{
name: "Empty CertFile",
input: grpc.SignerConfig{
CAPool: []string{"ca1.pem"},
KeyFile: urischeme.URIScheme("key.pem"),
CertFile: "",
ValidFrom: time.Now().Format(time.RFC3339),
ExpiresIn: time.Hour * 24,
CRL: crl,
},
wantErr: true,
},
{
name: "Empty KeyFile",
input: grpc.SignerConfig{
CAPool: []string{"ca1.pem"},
KeyFile: "",
CertFile: urischeme.URIScheme("cert.pem"),
ValidFrom: time.Now().Format(time.RFC3339),
ExpiresIn: time.Hour * 24,
CRL: crl,
},
wantErr: true,
},
{
name: "Invalid ExpiresIn",
input: grpc.SignerConfig{
CAPool: []string{"ca1.pem", "ca2.pem"},
KeyFile: urischeme.URIScheme("key.pem"),
CertFile: urischeme.URIScheme("cert.pem"),
ValidFrom: time.Now().Format(time.RFC3339),
ExpiresIn: -1,
CRL: crl,
},
wantErr: true,
},
{
name: "Invalid ValidFrom format",
input: grpc.SignerConfig{
CAPool: []string{"ca1.pem"},
KeyFile: urischeme.URIScheme("key.pem"),
CertFile: urischeme.URIScheme("cert.pem"),
ValidFrom: "invalid-date",
ExpiresIn: time.Hour * 24,
CRL: crl,
},
wantErr: true,
},
{
name: "Invalid CRL",
input: grpc.SignerConfig{
CAPool: []string{"ca1.pem", "ca2.pem"},
KeyFile: urischeme.URIScheme("key.pem"),
CertFile: urischeme.URIScheme("cert.pem"),
ValidFrom: time.Now().Format(time.RFC3339),
ExpiresIn: time.Hour * 24,
CRL: grpc.CRLConfig{
Enabled: true,
},
},
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)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ func TestCertificateAuthorityServerDeleteSigningRecords(t *testing.T) {
{
name: "missing token with ownerClaim in ctx",
args: args{
req: &pb.DeleteSigningRecordsRequest{
IdFilter: []string{r.GetId()},
},
ctx: context.Background(),
},
wantErr: true,
Expand Down Expand Up @@ -103,7 +106,7 @@ func TestCertificateAuthorityServerDeleteSigningRecords(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := grpcClient.DeleteSigningRecords(ctx, tt.args.req)
got, err := grpcClient.DeleteSigningRecords(tt.args.ctx, tt.args.req)
if tt.wantErr {
require.Error(t, err)
return
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.signerConfig)
signer, err := NewSigner(s.ownerClaim, s.hubID, s.crlServerAddress, s.signerConfig)
if err != nil {
return false, fmt.Errorf("cannot create signer: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion certificate-authority/service/grpc/signCertificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (s *CertificateAuthorityServer) updateSigningRecord(ctx context.Context, si
// revoke previous signing record
prevCred := prevSr.GetCredential()
if prevCred != nil {
err = s.store.RevokeCertificates(ctx, prevCred.GetIssuerId(), &store.RevocationListCertificate{
_, err = s.store.RevokeCertificates(ctx, prevCred.GetIssuerId(), &store.RevocationListCertificate{
Serial: prevCred.GetSerial(),
Expiration: prevCred.GetValidUntilDate(),
Revocation: time.Now().UnixNano(),
Expand Down
10 changes: 5 additions & 5 deletions certificate-authority/service/grpc/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func getIssuerID(rootCertificate *x509.Certificate) (string, error) {
return uuid.NewSHA1(uuid.NameSpaceX500, publicKeyRaw).String(), nil
}

func newSigner(ownerClaim, hubID string, signerConfig SignerConfig, privateKey *ecdsa.PrivateKey, certificate []*x509.Certificate) (*Signer, error) {
func newSigner(ownerClaim, hubID, crlServerAddress string, signerConfig SignerConfig, privateKey *ecdsa.PrivateKey, certificate []*x509.Certificate) (*Signer, error) {
issuerID, err := getIssuerID(certificate[0])
if err != nil {
return nil, err
Expand All @@ -71,13 +71,13 @@ func newSigner(ownerClaim, hubID string, signerConfig SignerConfig, privateKey *
hubID: hubID,
}
if signerConfig.CRL.Enabled {
signer.crl.serverAddress = signerConfig.CRL.ExternalAddress
signer.crl.serverAddress = crlServerAddress
signer.crl.validFor = signerConfig.CRL.ExpiresIn
}
return signer, nil
}

func NewSigner(ownerClaim, hubID string, signerConfig SignerConfig) (*Signer, error) {
func NewSigner(ownerClaim, hubID, crlServerAddress string, signerConfig SignerConfig) (*Signer, error) {
data, err := signerConfig.CertFile.Read()
if err != nil {
return nil, err
Expand All @@ -98,7 +98,7 @@ func NewSigner(ownerClaim, hubID string, signerConfig SignerConfig) (*Signer, er
return nil, err
}
if len(certificate) == 1 && pkgX509.IsRootCA(certificate[0]) {
return newSigner(ownerClaim, hubID, signerConfig, privateKey, certificate)
return newSigner(ownerClaim, hubID, crlServerAddress, signerConfig, privateKey, certificate)
}
certificateAuthorities := make([]*x509.Certificate, 0, len(signerConfig.caPoolArray)*4)
for _, caFile := range signerConfig.caPoolArray {
Expand All @@ -120,7 +120,7 @@ func NewSigner(ownerClaim, hubID string, signerConfig SignerConfig) (*Signer, er
if err != nil {
return nil, err
}
return newSigner(ownerClaim, hubID, signerConfig, privateKey, chains[0])
return newSigner(ownerClaim, hubID, crlServerAddress, signerConfig, privateKey, chains[0])
}

func (s *Signer) prepareSigningRecord(ctx context.Context, template *x509.Certificate) (*pb.SigningRecord, error) {
Expand Down
2 changes: 1 addition & 1 deletion certificate-authority/service/grpc/signer_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestNewSigner(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewSigner("tt.args.ownerClaim", "tt.args.hubID", tt.args.signerConfig)
got, err := NewSigner("ownerClaim", "hubID", "", tt.args.signerConfig)
if tt.wantErr {
require.Error(t, err)
return
Expand Down
Loading

0 comments on commit 1be10f8

Please sign in to comment.