Skip to content

Commit 4db48dc

Browse files
committed
fips: check provided fulcio crypto for fips compliance
1 parent 3d48a98 commit 4db48dc

File tree

4 files changed

+386
-0
lines changed

4 files changed

+386
-0
lines changed

internal/controller/fulcio/actions/generate_cert.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/securesign/operator/internal/controller/fulcio/utils"
1616
"github.com/securesign/operator/internal/labels"
1717
utils2 "github.com/securesign/operator/internal/utils"
18+
cryptoutil "github.com/securesign/operator/internal/utils/crypto"
1819
"github.com/securesign/operator/internal/utils/kubernetes"
1920
"github.com/securesign/operator/internal/utils/kubernetes/ensure"
2021
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -210,6 +211,11 @@ func (g handleCert) setupCert(instance *v1alpha1.Fulcio) (*utils.FulcioCertConfi
210211
if err != nil {
211212
return nil, err
212213
}
214+
if cryptoutil.FIPSEnabled {
215+
if err := cryptoutil.ValidatePrivateKeyPEM(key, config.PrivateKeyPassword); err != nil {
216+
return nil, err
217+
}
218+
}
213219
config.PrivateKey = key
214220
} else {
215221
key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
@@ -235,6 +241,11 @@ func (g handleCert) setupCert(instance *v1alpha1.Fulcio) (*utils.FulcioCertConfi
235241
if err != nil {
236242
return nil, err
237243
}
244+
if cryptoutil.FIPSEnabled {
245+
if err := cryptoutil.ValidateCertificatePEM(key); err != nil {
246+
return nil, err
247+
}
248+
}
238249
config.RootCert = key
239250
} else {
240251
rootCert, err := utils.CreateFulcioCA(config)

internal/controller/fulcio/actions/generate_cert_test.go

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"github.com/securesign/operator/internal/controller/fulcio/utils"
1515
"github.com/securesign/operator/internal/labels"
1616
testAction "github.com/securesign/operator/internal/testing/action"
17+
cryptoutil "github.com/securesign/operator/internal/utils/crypto"
18+
fipsTest "github.com/securesign/operator/internal/utils/crypto/test"
1719
"github.com/securesign/operator/internal/utils/kubernetes"
1820
v1 "k8s.io/api/core/v1"
1921
"k8s.io/apimachinery/pkg/api/errors"
@@ -447,3 +449,222 @@ func TestGenerateCert_Handle(t *testing.T) {
447449
})
448450
}
449451
}
452+
453+
func TestGenerateCert_Handle_FIPS(t *testing.T) {
454+
ctx := context.TODO()
455+
g := NewWithT(t)
456+
cryptoutil.FIPSEnabled = true
457+
t.Cleanup(func() {
458+
cryptoutil.FIPSEnabled = false
459+
})
460+
461+
_, invalidPriv, invalidCert, err := fipsTest.GenerateECCertificatePEM(false, "", elliptic.P224())
462+
g.Expect(err).NotTo(HaveOccurred())
463+
464+
_, validPriv, validCert, err := fipsTest.GenerateECCertificatePEM(false, "", elliptic.P256())
465+
g.Expect(err).NotTo(HaveOccurred())
466+
467+
type env struct {
468+
spec rhtasv1alpha1.FulcioCert
469+
status rhtasv1alpha1.FulcioStatus
470+
objects []client.Object
471+
}
472+
473+
type want struct {
474+
result *action.Result
475+
certCondition metav1.ConditionStatus
476+
}
477+
478+
tests := []struct {
479+
name string
480+
env env
481+
want want
482+
}{
483+
{
484+
name: "valid private key (EC P256)",
485+
env: env{
486+
spec: rhtasv1alpha1.FulcioCert{
487+
OrganizationName: "RH",
488+
OrganizationEmail: "jdoe@redhat.com",
489+
PrivateKeyRef: &rhtasv1alpha1.SecretKeySelector{
490+
LocalObjectReference: rhtasv1alpha1.LocalObjectReference{
491+
Name: "fulcio-private-valid",
492+
},
493+
Key: "private",
494+
},
495+
},
496+
status: rhtasv1alpha1.FulcioStatus{},
497+
objects: []client.Object{
498+
&v1.Secret{
499+
ObjectMeta: metav1.ObjectMeta{
500+
Name: "fulcio-private-valid",
501+
Namespace: "default",
502+
},
503+
Data: map[string][]byte{
504+
"private": validPriv,
505+
},
506+
},
507+
},
508+
},
509+
want: want{
510+
result: testAction.StatusUpdate(),
511+
certCondition: metav1.ConditionTrue,
512+
},
513+
},
514+
{
515+
name: "invalid private key (EC P224)",
516+
env: env{
517+
spec: rhtasv1alpha1.FulcioCert{
518+
OrganizationName: "RH",
519+
OrganizationEmail: "jdoe@redhat.com",
520+
PrivateKeyRef: &rhtasv1alpha1.SecretKeySelector{
521+
LocalObjectReference: rhtasv1alpha1.LocalObjectReference{
522+
Name: "fulcio-private-invalid",
523+
},
524+
Key: "private",
525+
},
526+
},
527+
status: rhtasv1alpha1.FulcioStatus{},
528+
objects: []client.Object{
529+
&v1.Secret{
530+
ObjectMeta: metav1.ObjectMeta{
531+
Name: "fulcio-private-invalid",
532+
Namespace: "default",
533+
},
534+
Data: map[string][]byte{
535+
"private": invalidPriv,
536+
},
537+
},
538+
},
539+
},
540+
want: want{
541+
result: testAction.Requeue(),
542+
certCondition: metav1.ConditionFalse,
543+
},
544+
},
545+
{
546+
name: "valid CA certificate (EC P256)",
547+
env: env{
548+
spec: rhtasv1alpha1.FulcioCert{
549+
OrganizationName: "RH",
550+
OrganizationEmail: "jdoe@redhat.com",
551+
PrivateKeyRef: &rhtasv1alpha1.SecretKeySelector{
552+
LocalObjectReference: rhtasv1alpha1.LocalObjectReference{
553+
Name: "fulcio-private-valid",
554+
},
555+
Key: "private",
556+
},
557+
CARef: &rhtasv1alpha1.SecretKeySelector{
558+
LocalObjectReference: rhtasv1alpha1.LocalObjectReference{
559+
Name: "fulcio-ca-valid",
560+
},
561+
Key: "cert",
562+
},
563+
},
564+
status: rhtasv1alpha1.FulcioStatus{},
565+
objects: []client.Object{
566+
&v1.Secret{
567+
ObjectMeta: metav1.ObjectMeta{
568+
Name: "fulcio-private-valid",
569+
Namespace: "default",
570+
},
571+
Data: map[string][]byte{
572+
"private": validPriv,
573+
},
574+
},
575+
&v1.Secret{
576+
ObjectMeta: metav1.ObjectMeta{
577+
Name: "fulcio-ca-valid",
578+
Namespace: "default",
579+
},
580+
Data: map[string][]byte{
581+
"cert": validCert,
582+
},
583+
},
584+
},
585+
},
586+
want: want{
587+
result: testAction.StatusUpdate(),
588+
certCondition: metav1.ConditionTrue,
589+
},
590+
},
591+
{
592+
name: "invalid CA certificate (EC P224)",
593+
env: env{
594+
spec: rhtasv1alpha1.FulcioCert{
595+
OrganizationName: "RH",
596+
OrganizationEmail: "jdoe@redhat.com",
597+
PrivateKeyRef: &rhtasv1alpha1.SecretKeySelector{
598+
LocalObjectReference: rhtasv1alpha1.LocalObjectReference{
599+
Name: "fulcio-private-valid",
600+
},
601+
Key: "private",
602+
},
603+
CARef: &rhtasv1alpha1.SecretKeySelector{
604+
LocalObjectReference: rhtasv1alpha1.LocalObjectReference{
605+
Name: "fulcio-ca-invalid",
606+
},
607+
Key: "cert",
608+
},
609+
},
610+
status: rhtasv1alpha1.FulcioStatus{},
611+
objects: []client.Object{
612+
&v1.Secret{
613+
ObjectMeta: metav1.ObjectMeta{
614+
Name: "fulcio-private-valid",
615+
Namespace: "default",
616+
},
617+
Data: map[string][]byte{
618+
"private": validPriv,
619+
},
620+
},
621+
&v1.Secret{
622+
ObjectMeta: metav1.ObjectMeta{
623+
Name: "fulcio-ca-invalid",
624+
Namespace: "default",
625+
},
626+
Data: map[string][]byte{
627+
"cert": invalidCert,
628+
},
629+
},
630+
},
631+
},
632+
want: want{
633+
result: testAction.Requeue(),
634+
certCondition: metav1.ConditionFalse,
635+
},
636+
},
637+
}
638+
639+
for _, tt := range tests {
640+
t.Run(tt.name, func(t *testing.T) {
641+
instance := &rhtasv1alpha1.Fulcio{
642+
ObjectMeta: metav1.ObjectMeta{
643+
Name: "instance",
644+
Namespace: "default",
645+
},
646+
Spec: rhtasv1alpha1.FulcioSpec{
647+
Certificate: tt.env.spec,
648+
},
649+
Status: tt.env.status,
650+
}
651+
instance.SetCondition(metav1.Condition{
652+
Type: constants.Ready,
653+
Reason: constants.Pending,
654+
})
655+
656+
c := testAction.FakeClientBuilder().
657+
WithObjects(instance).
658+
WithStatusSubresource(instance).
659+
WithObjects(tt.env.objects...).
660+
Build()
661+
662+
a := testAction.PrepareAction(c, NewHandleCertAction())
663+
g.Expect(a.CanHandle(ctx, instance)).To(BeTrue())
664+
665+
res := a.Handle(ctx, instance)
666+
g.Expect(res).To(Equal(tt.want.result))
667+
g.Expect(meta.IsStatusConditionPresentAndEqual(instance.Status.Conditions, CertCondition, tt.want.certCondition)).To(BeTrue())
668+
})
669+
}
670+
}

0 commit comments

Comments
 (0)