@@ -50,9 +50,23 @@ def initialize(machine)
5050 def next_state
5151 Puppet . debug ( "Loading CA certs" )
5252
53+ force_crl_refresh = false
54+
5355 cacerts = @cert_provider . load_cacerts
5456 if cacerts
5557 next_ctx = @ssl_provider . create_root_context ( cacerts : cacerts , revocation : false )
58+
59+ now = Time . now
60+ last_update = @cert_provider . ca_last_update
61+ if needs_refresh? ( now , last_update )
62+ # set last updated time first, then make a best effort to refresh
63+ @cert_provider . ca_last_update = now
64+
65+ # If we refresh the CA, then we need to force the CRL to be refreshed too,
66+ # since if there is a new CA in the chain, then we need its CRL to check
67+ # the full chain for revocation status.
68+ next_ctx , force_crl_refresh = refresh_ca ( next_ctx , last_update )
69+ end
5670 else
5771 route = @machine . session . route_to ( :ca , ssl_context : @ssl_context )
5872 _ , pem = route . get_certificate ( Puppet ::SSL ::CA_NAME , ssl_context : @ssl_context )
@@ -74,7 +88,7 @@ def next_state
7488 @cert_provider . save_cacerts ( cacerts )
7589 end
7690
77- NeedCRLs . new ( @machine , next_ctx )
91+ NeedCRLs . new ( @machine , next_ctx , force_crl_refresh )
7892 rescue OpenSSL ::X509 ::CertificateError => e
7993 Error . new ( @machine , e . message , e )
8094 rescue Puppet ::HTTP ::ResponseError => e
@@ -84,6 +98,49 @@ def next_state
8498 to_error ( _ ( 'Could not download CA certificate: %{message}' ) % { message : e . message } , e )
8599 end
86100 end
101+
102+ private
103+
104+ def needs_refresh? ( now , last_update )
105+ return true if last_update . nil?
106+
107+ ca_ttl = Puppet [ :ca_refresh_interval ]
108+ return false unless ca_ttl
109+
110+ now . to_i > last_update . to_i + ca_ttl
111+ end
112+
113+ def refresh_ca ( ssl_ctx , last_update )
114+ Puppet . info ( _ ( "Refreshing CA certificate" ) )
115+
116+ # return the next_ctx containing the updated ca
117+ [ download_ca ( ssl_ctx , last_update ) , true ]
118+ rescue Puppet ::HTTP ::ResponseError => e
119+ if e . response . code == 304
120+ Puppet . info ( _ ( "CA certificate is unmodified, using existing CA certificate" ) )
121+ else
122+ Puppet . info ( _ ( "Failed to refresh CA certificate, using existing CA certificate: %{message}" ) % { message : e . message } )
123+ end
124+
125+ # return the original ssl_ctx
126+ [ ssl_ctx , false ]
127+ rescue Puppet ::HTTP ::HTTPError => e
128+ Puppet . warning ( _ ( "Failed to refresh CA certificate, using existing CA certificate: %{message}" ) % { message : e . message } )
129+
130+ # return the original ssl_ctx
131+ [ ssl_ctx , false ]
132+ end
133+
134+ def download_ca ( ssl_ctx , last_update )
135+ route = @machine . session . route_to ( :ca , ssl_context : ssl_ctx )
136+ _ , pem = route . get_certificate ( Puppet ::SSL ::CA_NAME , if_modified_since : last_update , ssl_context : ssl_ctx )
137+ cacerts = @cert_provider . load_cacerts_from_pem ( pem )
138+ # verify cacerts before saving
139+ next_ctx = @ssl_provider . create_root_context ( cacerts : cacerts , revocation : false )
140+ @cert_provider . save_cacerts ( cacerts )
141+
142+ next_ctx
143+ end
87144 end
88145
89146 # If revocation is enabled, load CRLs or download them, using the CA bundle
@@ -93,6 +150,13 @@ def next_state
93150 # for which we don't have a CRL
94151 #
95152 class NeedCRLs < SSLState
153+ attr_reader :force_crl_refresh
154+
155+ def initialize ( machine , ssl_context , force_crl_refresh = false )
156+ super ( machine , ssl_context )
157+ @force_crl_refresh = force_crl_refresh
158+ end
159+
96160 def next_state
97161 Puppet . debug ( "Loading CRLs" )
98162
@@ -102,15 +166,12 @@ def next_state
102166 if crls
103167 next_ctx = @ssl_provider . create_root_context ( cacerts : ssl_context [ :cacerts ] , crls : crls )
104168
105- crl_ttl = Puppet [ :crl_refresh_interval ]
106- if crl_ttl
107- last_update = @cert_provider . crl_last_update
108- now = Time . now
109- if last_update . nil? || now . to_i > last_update . to_i + crl_ttl
110- # set last updated time first, then make a best effort to refresh
111- @cert_provider . crl_last_update = now
112- next_ctx = refresh_crl ( next_ctx , last_update )
113- end
169+ now = Time . now
170+ last_update = @cert_provider . crl_last_update
171+ if needs_refresh? ( now , last_update )
172+ # set last updated time first, then make a best effort to refresh
173+ @cert_provider . crl_last_update = now
174+ next_ctx = refresh_crl ( next_ctx , last_update )
114175 end
115176 else
116177 next_ctx = download_crl ( @ssl_context , nil )
@@ -133,6 +194,15 @@ def next_state
133194
134195 private
135196
197+ def needs_refresh? ( now , last_update )
198+ return true if @force_crl_refresh || last_update . nil?
199+
200+ crl_ttl = Puppet [ :crl_refresh_interval ]
201+ return false unless crl_ttl
202+
203+ now . to_i > last_update . to_i + crl_ttl
204+ end
205+
136206 def refresh_crl ( ssl_ctx , last_update )
137207 Puppet . info ( _ ( "Refreshing CRL" ) )
138208
0 commit comments