Skip to content

Commit 64e4be2

Browse files
committed
feat: add fips check for ctlog
1 parent 1a49699 commit 64e4be2

File tree

5 files changed

+576
-3
lines changed

5 files changed

+576
-3
lines changed

internal/controller/ctlog/actions/handle_keys.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/securesign/operator/internal/constants"
1212
"github.com/securesign/operator/internal/controller/ctlog/utils"
1313
"github.com/securesign/operator/internal/labels"
14+
cryptoutil "github.com/securesign/operator/internal/utils/crypto"
1415
"github.com/securesign/operator/internal/utils/kubernetes"
1516
"github.com/securesign/operator/internal/utils/kubernetes/ensure"
1617
v1 "k8s.io/api/core/v1"
@@ -77,10 +78,26 @@ func (g handleKeys) Handle(ctx context.Context, instance *v1alpha1.CTlog) *actio
7778

7879
keys, err := g.setupKeys(instance.Namespace, newKeyStatus)
7980
if err != nil {
80-
return g.Error(ctx, fmt.Errorf("could not generate keys: %w", err), instance)
81+
meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
82+
Type: ConfigCondition,
83+
Status: metav1.ConditionFalse,
84+
Reason: SignerKeyReason,
85+
Message: fmt.Sprintf("Waiting for Ctlog signer key: %v", err),
86+
ObservedGeneration: instance.Generation,
87+
})
88+
g.StatusUpdate(ctx, instance)
89+
return g.Requeue()
8190
}
8291
if _, err = g.generateAndUploadSecret(ctx, instance, newKeyStatus, keys); err != nil {
83-
return g.Error(ctx, fmt.Errorf("could not generate Secret: %w", err), instance)
92+
meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
93+
Type: ConfigCondition,
94+
Status: metav1.ConditionFalse,
95+
Reason: SignerKeyReason,
96+
Message: fmt.Sprintf("Waiting for Ctlog signer key: %v", err),
97+
ObservedGeneration: instance.Generation,
98+
})
99+
g.StatusUpdate(ctx, instance)
100+
return g.Requeue()
84101
}
85102

86103
instance.Status = *newKeyStatus
@@ -122,6 +139,11 @@ func (g handleKeys) setupKeys(ns string, instanceStatus *v1alpha1.CTlogStatus) (
122139
if err != nil {
123140
return nil, err
124141
}
142+
if cryptoutil.FIPSEnabled {
143+
if err := cryptoutil.ValidatePrivateKeyPEM(config.PrivateKey, config.PrivateKeyPass); err != nil {
144+
return nil, err
145+
}
146+
}
125147
}
126148

127149
if instanceStatus.PublicKeyRef == nil {
@@ -131,6 +153,11 @@ func (g handleKeys) setupKeys(ns string, instanceStatus *v1alpha1.CTlogStatus) (
131153
if err != nil {
132154
return nil, err
133155
}
156+
if cryptoutil.FIPSEnabled {
157+
if err := cryptoutil.ValidatePublicKeyPEM(config.PublicKey); err != nil {
158+
return nil, err
159+
}
160+
}
134161
return config, nil
135162
}
136163
}

internal/controller/ctlog/actions/handle_keys_test.go

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package actions
22

33
import (
44
"context"
5+
"crypto/elliptic"
56
"reflect"
67
"testing"
78

@@ -11,6 +12,8 @@ import (
1112
"github.com/securesign/operator/internal/labels"
1213
testAction "github.com/securesign/operator/internal/testing/action"
1314
utils2 "github.com/securesign/operator/internal/utils"
15+
cryptoutil "github.com/securesign/operator/internal/utils/crypto"
16+
fipsTest "github.com/securesign/operator/internal/utils/crypto/test"
1417
"github.com/securesign/operator/internal/utils/kubernetes"
1518
"k8s.io/apimachinery/pkg/watch"
1619
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -565,3 +568,185 @@ func TestKeys_Handle(t *testing.T) {
565568
})
566569
}
567570
}
571+
572+
func TestKeys_Handle_FIPS(t *testing.T) {
573+
cryptoutil.FIPSEnabled = true
574+
t.Cleanup(func() {
575+
cryptoutil.FIPSEnabled = false
576+
})
577+
578+
type env struct {
579+
spec v1alpha1.CTlogSpec
580+
objects []client.Object
581+
status v1alpha1.CTlogStatus
582+
}
583+
584+
type want struct {
585+
expectError bool
586+
result *action.Result
587+
}
588+
589+
tests := []struct {
590+
name string
591+
env env
592+
want want
593+
}{
594+
{
595+
name: "valid private key (EC P256)",
596+
env: env{
597+
spec: v1alpha1.CTlogSpec{
598+
PrivateKeyRef: &v1alpha1.SecretKeySelector{
599+
LocalObjectReference: v1alpha1.LocalObjectReference{
600+
Name: "privateKey",
601+
},
602+
Key: "private",
603+
},
604+
},
605+
status: v1alpha1.CTlogStatus{},
606+
objects: []client.Object{
607+
&v1.Secret{
608+
ObjectMeta: metav1.ObjectMeta{
609+
Name: "privateKey",
610+
Namespace: "default",
611+
},
612+
Data: map[string][]byte{
613+
"private": fipsTest.GenerateECPrivateKeyPEM(t, elliptic.P256()),
614+
},
615+
},
616+
},
617+
},
618+
want: want{
619+
expectError: false,
620+
result: testAction.StatusUpdate(),
621+
},
622+
},
623+
{
624+
name: "valid public key",
625+
env: env{
626+
spec: v1alpha1.CTlogSpec{
627+
PublicKeyRef: &v1alpha1.SecretKeySelector{
628+
LocalObjectReference: v1alpha1.LocalObjectReference{
629+
Name: "pubKey",
630+
},
631+
Key: "public",
632+
},
633+
},
634+
status: v1alpha1.CTlogStatus{},
635+
objects: []client.Object{
636+
&v1.Secret{
637+
ObjectMeta: metav1.ObjectMeta{
638+
Name: "pubKey",
639+
Namespace: "default",
640+
}, Data: map[string][]byte{
641+
"public": fipsTest.GenerateECPublicKeyPEM(t, elliptic.P256()),
642+
},
643+
},
644+
},
645+
},
646+
want: want{
647+
expectError: false,
648+
result: testAction.StatusUpdate(),
649+
},
650+
},
651+
{
652+
name: "invalid private key (EC P224)",
653+
env: env{
654+
spec: v1alpha1.CTlogSpec{
655+
PrivateKeyRef: &v1alpha1.SecretKeySelector{
656+
LocalObjectReference: v1alpha1.LocalObjectReference{
657+
Name: "bad",
658+
},
659+
Key: "private",
660+
},
661+
},
662+
status: v1alpha1.CTlogStatus{},
663+
objects: []client.Object{
664+
&v1.Secret{
665+
ObjectMeta: metav1.ObjectMeta{
666+
Name: "bad",
667+
Namespace: "default",
668+
},
669+
Data: map[string][]byte{
670+
"private": fipsTest.GenerateECPrivateKeyPEM(t, elliptic.P224()),
671+
},
672+
},
673+
},
674+
},
675+
want: want{
676+
expectError: false,
677+
result: testAction.Requeue(),
678+
},
679+
},
680+
{
681+
name: "invalid public key",
682+
env: env{
683+
spec: v1alpha1.CTlogSpec{
684+
PrivateKeyRef: &v1alpha1.SecretKeySelector{
685+
LocalObjectReference: v1alpha1.LocalObjectReference{
686+
Name: "privateKey",
687+
}, Key: "private",
688+
},
689+
PublicKeyRef: &v1alpha1.SecretKeySelector{
690+
LocalObjectReference: v1alpha1.LocalObjectReference{
691+
Name: "badPubKey",
692+
},
693+
Key: "public",
694+
},
695+
},
696+
status: v1alpha1.CTlogStatus{},
697+
objects: []client.Object{
698+
&v1.Secret{
699+
ObjectMeta: metav1.ObjectMeta{
700+
Name: "badPubKey",
701+
Namespace: "default",
702+
},
703+
Data: map[string][]byte{
704+
"public": fipsTest.GenerateECPublicKeyPEM(t, elliptic.P224()),
705+
},
706+
},
707+
&v1.Secret{
708+
ObjectMeta: metav1.ObjectMeta{
709+
Name: "privateKey",
710+
Namespace: "default",
711+
},
712+
Data: map[string][]byte{"private": fipsTest.GenerateECPrivateKeyPEM(t, elliptic.P256())},
713+
},
714+
},
715+
},
716+
want: want{
717+
expectError: false,
718+
result: testAction.Requeue(),
719+
},
720+
},
721+
}
722+
for _, tt := range tests {
723+
t.Run(tt.name, func(t *testing.T) {
724+
ctx := context.TODO()
725+
instance := &v1alpha1.CTlog{
726+
ObjectMeta: metav1.ObjectMeta{Name: "instance", Namespace: "default"},
727+
Spec: tt.env.spec,
728+
Status: tt.env.status,
729+
}
730+
meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{Type: constants.Ready, Reason: constants.Creating})
731+
732+
c := testAction.FakeClientBuilder().
733+
WithObjects(instance).
734+
WithStatusSubresource(instance).
735+
WithObjects(tt.env.objects...).
736+
Build()
737+
a := testAction.PrepareAction(c, NewHandleKeysAction())
738+
res := a.Handle(ctx, instance)
739+
740+
if tt.want.expectError {
741+
if !action.IsError(res) {
742+
t.Fatalf("expected error result, got: %#v", res)
743+
}
744+
return
745+
}
746+
747+
if !reflect.DeepEqual(res, tt.want.result) {
748+
t.Errorf("Handle() = %v, want %v", res, tt.want.result)
749+
}
750+
})
751+
}
752+
}

internal/controller/ctlog/actions/server_config.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
ctlogUtils "github.com/securesign/operator/internal/controller/ctlog/utils"
1414
trillian "github.com/securesign/operator/internal/controller/trillian/actions"
1515
"github.com/securesign/operator/internal/labels"
16+
cryptoutil "github.com/securesign/operator/internal/utils/crypto"
1617
"github.com/securesign/operator/internal/utils/kubernetes"
1718
"github.com/securesign/operator/internal/utils/kubernetes/ensure"
1819
corev1 "k8s.io/api/core/v1"
@@ -108,7 +109,7 @@ func (i serverConfig) Handle(ctx context.Context, instance *rhtasv1alpha1.CTlog)
108109
Type: ConfigCondition,
109110
Status: metav1.ConditionFalse,
110111
Reason: SignerKeyReason,
111-
Message: "Waiting for Ctlog private key secret",
112+
Message: fmt.Sprintf("Waiting for Ctlog private key secret: %v", err),
112113
ObservedGeneration: instance.Generation,
113114
})
114115
i.StatusUpdate(ctx, instance)
@@ -211,6 +212,15 @@ func (i serverConfig) handlePrivateKey(instance *rhtasv1alpha1.CTlog) (*ctlogUti
211212
return nil, err
212213
}
213214

215+
if cryptoutil.FIPSEnabled {
216+
if err := cryptoutil.ValidatePrivateKeyPEM(private, password); err != nil {
217+
return nil, err
218+
}
219+
if err := cryptoutil.ValidatePublicKeyPEM(public); err != nil {
220+
return nil, err
221+
}
222+
}
223+
214224
return &ctlogUtils.KeyConfig{
215225
PrivateKey: private,
216226
PublicKey: public,

0 commit comments

Comments
 (0)