5
5
"fmt"
6
6
"os"
7
7
"path/filepath"
8
+ "time"
8
9
9
10
"github.com/massalabs/station/int/configuration"
10
11
"github.com/massalabs/station/pkg/certificate"
@@ -28,31 +29,19 @@ func Check() error {
28
29
29
30
certPath := filepath .Join (caRootPath , configuration .CertificateAuthorityFileName )
30
31
31
- isBrandNewCA := false
32
-
33
- _ , err = os .Stat (certPath )
34
- if os .IsNotExist (err ) {
35
- err = certificate .GenerateCA (
36
- configuration .OrganizationName ,
37
- configuration .CertificateAuthorityKeyFileName ,
38
- configuration .CertificateAuthorityFileName ,
39
- caRootPath ,
40
- )
41
- if err != nil {
42
- return caNonBlockingError ("failed to generate new CA" , err )
43
- }
44
-
45
- logger .Infof ("A new CA was generated at %s." , certPath )
46
-
47
- // A new CA was generated, we need to clean the certificates.
48
- isBrandNewCA = true
32
+ // Ensure CA certificate exists and is valid
33
+ isBrandNewCA , err := ensureValidCA (certPath , caRootPath )
34
+ if err != nil {
35
+ return caNonBlockingError ("failed to ensure valid CA" , err )
49
36
}
50
37
38
+ // Check certificate in system store
51
39
err = checkCertificate (certPath )
52
40
if err != nil {
53
41
resultErr = caNonBlockingError ("Error while checking certificate" , err )
54
42
}
55
43
44
+ // Check NSS configuration
56
45
err = checkNSS (certPath , isBrandNewCA )
57
46
if err != nil {
58
47
resultErr = caNonBlockingError ("Error while checking NSS" , err )
@@ -61,6 +50,54 @@ func Check() error {
61
50
return resultErr
62
51
}
63
52
53
+ // ensureValidCA ensures that a valid CA certificate exists at the specified path.
54
+ // It returns true if a new CA was generated, false if existing CA is valid.
55
+ func ensureValidCA (certPath , caRootPath string ) (bool , error ) {
56
+ // Check if certificate file exists
57
+ _ , err := os .Stat (certPath )
58
+ if os .IsNotExist (err ) {
59
+ logger .Infof ("Certificate file does not exist, generating new CA..." )
60
+ return true , generateCA (caRootPath , "certificate file does not exist" )
61
+ }
62
+
63
+ // Certificate file exists, validate it
64
+ existingCert , loadErr := certificate .LoadCertificate (certPath )
65
+ if loadErr != nil {
66
+ logger .Warnf ("Failed to load existing certificate: %v, generating new one" , loadErr )
67
+ return true , generateCA (caRootPath , "failed to load existing certificate" )
68
+ }
69
+
70
+ // Check if certificate is expired
71
+ if existingCert .NotAfter .Before (time .Now ()) {
72
+ logger .Warnf ("Certificate is expired (NotAfter=%s), generating new one" , existingCert .NotAfter .String ())
73
+ return true , generateCA (caRootPath , "certificate is expired" )
74
+ }
75
+
76
+ // Certificate is valid
77
+ logger .Debugf ("Certificate is valid until %s" , existingCert .NotAfter .String ())
78
+ return false , nil
79
+ }
80
+
81
+ // generateCA generates a new CA certificate with consistent parameters and logging.
82
+ func generateCA (caRootPath , reason string ) error {
83
+ logger .Infof ("Generating new CA certificate (reason: %s)..." , reason )
84
+
85
+ err := certificate .GenerateCA (
86
+ configuration .OrganizationName ,
87
+ configuration .CertificateAuthorityKeyFileName ,
88
+ configuration .CertificateAuthorityFileName ,
89
+ caRootPath ,
90
+ )
91
+ if err != nil {
92
+ return fmt .Errorf ("failed to generate CA certificate: %w" , err )
93
+ }
94
+
95
+ certPath := filepath .Join (caRootPath , configuration .CertificateAuthorityFileName )
96
+ logger .Infof ("New CA certificate generated successfully at %s" , certPath )
97
+
98
+ return nil
99
+ }
100
+
64
101
// nonBlockingError logs a non blocking error. It always returns a `nil` error to be used in `return`.
65
102
func nonBlockingError (context string , consequence string , err error ) error {
66
103
if err != nil {
@@ -78,27 +115,49 @@ func caNonBlockingError(context string, err error) error {
78
115
79
116
// checkCertificate checks the certificate configuration.
80
117
func checkCertificate (certPath string ) error {
118
+ // Load certificate
119
+ certCA , err := loadCertificate (certPath )
120
+ if err != nil {
121
+ return err
122
+ }
123
+
124
+ // Check if certificate is trusted by the operating system
125
+ return ensureCertificateInSystemStore (certCA )
126
+ }
127
+
128
+ // loadCertificate loads a certificate.
129
+ func loadCertificate (certPath string ) (* x509.Certificate , error ) {
81
130
certCA , err := certificate .LoadCertificate (certPath )
82
131
if err != nil {
83
- return fmt .Errorf ("failed to load the CA: %w" , err )
132
+ return nil , fmt .Errorf ("failed to load the CA: %w" , err )
84
133
}
85
134
86
- // disable linting as we don't care about checking specific attributes
87
- //nolint:exhaustruct
88
- _ , err = certCA .Verify (x509.VerifyOptions {})
135
+ return certCA , nil
136
+ }
137
+
138
+ // ensureCertificateInSystemStore ensures the certificate is trusted by the operating system.
139
+ func ensureCertificateInSystemStore (certCA * x509.Certificate ) error {
140
+ // Check if certificate is already trusted by the OS
141
+ //nolint:exhaustruct // We don't care about checking specific attributes
142
+ _ , err := certCA .Verify (x509.VerifyOptions {})
89
143
if err != nil {
90
- logger .Debug ("the CA is not known by the operating system." )
144
+ logger .Debug ("Certificate is not trusted by the operating system, adding to store" )
145
+ return addCertificateToSystemStore (certCA )
146
+ }
91
147
92
- err := store .Add (certCA )
93
- if err != nil {
94
- return fmt .Errorf ("failed to add the CA to the operating system: %w" , err )
95
- }
148
+ logger .Debug ("Certificate is already trusted by the operating system" )
149
+ return nil
150
+ }
96
151
97
- logger .Debug ("the CA was added to the operating system." )
98
- } else {
99
- logger .Debug ("the CA is known by the operating system." )
152
+ // addCertificateToSystemStore adds a certificate to the operating system store.
153
+ func addCertificateToSystemStore (certCA * x509.Certificate ) error {
154
+ err := store .Add (certCA )
155
+ if err != nil {
156
+ logger .Errorf ("Failed to add certificate to operating system: %v" , err )
157
+ return fmt .Errorf ("failed to add the CA to the operating system: %w" , err )
100
158
}
101
159
160
+ logger .Debug ("Certificate successfully added to the operating system store" )
102
161
return nil
103
162
}
104
163
0 commit comments