@@ -69,6 +69,8 @@ const maxOCSPTries = 10
69
69
// TODO(banaag): make 2 days renewal grace period configurable in toml.
70
70
const certRenewalInterval = 8 * 24 * time .Hour
71
71
72
+ type OCSPResponder func (* x509.Certificate ) ([]byte , error )
73
+
72
74
type CertHandler interface {
73
75
GetLatestCert () * x509.Certificate
74
76
IsHealthy () error
@@ -90,6 +92,10 @@ type CertCache struct {
90
92
ocspFile Updateable
91
93
ocspFilePath string
92
94
client http.Client
95
+ // Given a certificate, returns a current OCSP response for the cert;
96
+ // this is a fallback, called when in development mode and there is no
97
+ // OCSP URL.
98
+ generateOCSPResponse OCSPResponder
93
99
// Domains to validate
94
100
Domains []string
95
101
CertFile string
@@ -114,7 +120,7 @@ type CertCache struct {
114
120
// An alternative pattern would be to create an IsInitialized() bool or similarly named function that verifies all of the required fields have
115
121
// been set. Then callers can just set fields in the struct by name and assert IsInitialized before doing anything with it.
116
122
func New (certs []* x509.Certificate , certFetcher * certfetcher.CertFetcher , domains []string ,
117
- certFile string , newCertFile string , ocspCache string ) * CertCache {
123
+ certFile string , newCertFile string , ocspCache string , generateOCSPResponse OCSPResponder ) * CertCache {
118
124
certName := ""
119
125
if len (certs ) > 0 && certs [0 ] != nil {
120
126
certName = util .CertName (certs [0 ])
@@ -135,6 +141,7 @@ func New(certs []*x509.Certificate, certFetcher *certfetcher.CertFetcher, domain
135
141
// you'd have one request, in the backend, and updating them all.
136
142
ocspFile : & Chained {first : & InMemory {}, second : & LocalFile {path : ocspCache }},
137
143
ocspFilePath : ocspCache ,
144
+ generateOCSPResponse : generateOCSPResponse ,
138
145
client : http.Client {Timeout : 60 * time .Second },
139
146
extractOCSPServer : func (cert * x509.Certificate ) (string , error ) {
140
147
if cert == nil || len (cert .OCSPServer ) < 1 {
@@ -441,8 +448,8 @@ func (this *CertCache) maintainOCSP(stop chan struct{}) {
441
448
}
442
449
443
450
// Returns true if OCSP is expired (or near enough).
444
- func (this * CertCache ) shouldUpdateOCSP (bytes []byte ) bool {
445
- if len (bytes ) == 0 {
451
+ func (this * CertCache ) shouldUpdateOCSP (ocsp []byte ) bool {
452
+ if len (ocsp ) == 0 {
446
453
// TODO(twifkak): Use a logging framework with support for debug-only statements.
447
454
log .Println ("Updating OCSP; none cached yet." )
448
455
return true
@@ -454,7 +461,7 @@ func (this *CertCache) shouldUpdateOCSP(bytes []byte) bool {
454
461
return false
455
462
}
456
463
// Compute the midpoint per sleevi #3 (see above).
457
- midpoint , err := this .ocspMidpoint (bytes , issuer )
464
+ midpoint , err := this .ocspMidpoint (ocsp , issuer )
458
465
if err != nil {
459
466
log .Println ("Error computing OCSP midpoint:" , err )
460
467
return true
@@ -537,8 +544,17 @@ func (this *CertCache) fetchOCSP(orig []byte, certs []*x509.Certificate, ocspUpd
537
544
538
545
ocspServer , err := this .extractOCSPServer (certs [0 ])
539
546
if err != nil {
540
- log .Println ("Error extracting OCSP server:" , err )
541
- return orig
547
+ if this .generateOCSPResponse == nil {
548
+ log .Println ("Error extracting OCSP server:" , err )
549
+ return orig
550
+ }
551
+ log .Println ("Cert lacks OCSP URL; using fake OCSP in development mode." )
552
+ resp , err := this .generateOCSPResponse (certs [0 ])
553
+ if err != nil {
554
+ log .Println ("error generating fake OCSP response:" , err )
555
+ return orig
556
+ }
557
+ return resp
542
558
}
543
559
544
560
// Conform to the Lightweight OCSP Profile, by preferring GET over POST
@@ -821,7 +837,7 @@ func (this *CertCache) reloadCertIfExpired() {
821
837
// Creates cert cache by loading certs and keys from disk, doing validation
822
838
// and populating the cert cache with current set of certificate related information.
823
839
// If development mode is true, prints a warning for certs that can't sign HTTP exchanges.
824
- func PopulateCertCache (config * util.Config , key crypto.PrivateKey ,
840
+ func PopulateCertCache (config * util.Config , key crypto.PrivateKey , generateOCSPResponse OCSPResponder ,
825
841
developmentMode bool , autoRenewCert bool ) (* CertCache , error ) {
826
842
827
843
if config .CertFile == "" {
@@ -851,7 +867,7 @@ func PopulateCertCache(config *util.Config, key crypto.PrivateKey,
851
867
if err != nil {
852
868
return nil , errors .Wrap (err , "creating cert fetcher from config" )
853
869
}
854
- certCache := New (certs , certFetcher , []string {domain }, config .CertFile , config .NewCertFile , config .OCSPCache )
870
+ certCache := New (certs , certFetcher , []string {domain }, config .CertFile , config .NewCertFile , config .OCSPCache , generateOCSPResponse )
855
871
856
872
return certCache , nil
857
873
}
0 commit comments