@@ -56,32 +56,80 @@ type CertCache struct {
56
56
57
57
const certificateFileName = "cert.pem"
58
58
const certificateBlockName = "CERTIFICATE"
59
+ const privateKeyFileName = "key.pem"
60
+ const privateKeyBlockName = "PRIVATE KEY"
59
61
60
62
func buildKeyString (hosts []string ) string {
61
63
key := strings .Join (hosts , ";" )
62
64
return key
63
65
}
64
66
65
67
func (c * CertCache ) writeCertificate (key string , cert * tls.Certificate ) (err error ) {
66
- leadingDirs , ok := c .buildPathToCachedCert (key )
68
+ leadingDir , ok := c .buildPathToCachedCert (key )
67
69
if ! ok {
68
70
return
69
71
}
70
- err = os .MkdirAll (leadingDirs , os .FileMode (0777 ))
72
+
73
+ leadingDirTmp := leadingDir + "$tmp$"
74
+ err = os .MkdirAll (leadingDirTmp , os .FileMode (0700 ))
71
75
if err != nil {
72
76
return
73
77
}
74
- path := filepath .Join (leadingDirs , certificateFileName )
75
- w , err := os .OpenFile (path , os .O_CREATE | os .O_TRUNC | os .O_WRONLY , os .FileMode (0666 ))
78
+ defer func () {
79
+ if err != nil {
80
+ os .RemoveAll (leadingDirTmp )
81
+ }
82
+ }()
83
+
84
+ certFilePath := filepath .Join (leadingDirTmp , certificateFileName )
85
+ privKeyFilePath := filepath .Join (leadingDirTmp , privateKeyFileName )
86
+
87
+ err = func (certFilePath string ) (err error ) {
88
+ w , err := os .OpenFile (certFilePath , os .O_CREATE | os .O_TRUNC | os .O_WRONLY , os .FileMode (0600 ))
89
+ if err != nil {
90
+ return
91
+ }
92
+ defer w .Close ()
93
+
94
+ for _ , x509Cert := range cert .Certificate {
95
+ err = pem .Encode (w , & pem.Block {Type : certificateBlockName , Bytes : x509Cert })
96
+ if err != nil {
97
+ return
98
+ }
99
+ _ , err = w .Write ([]byte {'\n' })
100
+ if err != nil {
101
+ return
102
+ }
103
+ }
104
+ return
105
+ }(certFilePath )
76
106
if err != nil {
77
107
return
78
108
}
79
- defer w .Close ()
80
- err = pem .Encode (w , & pem.Block {Type : certificateBlockName , Bytes : cert .Certificate [0 ]})
109
+
110
+ err = func (privKeyFilePath string ) (err error ) {
111
+ privKeyBytes , err := x509 .MarshalPKCS8PrivateKey (cert .PrivateKey )
112
+ if err != nil {
113
+ return
114
+ }
115
+
116
+ w , err := os .OpenFile (privKeyFilePath , os .O_CREATE | os .O_TRUNC | os .O_WRONLY , os .FileMode (0666 ))
117
+ if err != nil {
118
+ return
119
+ }
120
+ defer w .Close ()
121
+ err = pem .Encode (w , & pem.Block {Type : privateKeyBlockName , Bytes : privKeyBytes })
122
+ if err != nil {
123
+ return
124
+ }
125
+ return
126
+ }(privKeyFilePath )
81
127
if err != nil {
82
128
return
83
129
}
84
- return nil
130
+
131
+ err = os .Rename (leadingDirTmp , leadingDir )
132
+ return
85
133
}
86
134
87
135
func (c * CertCache ) buildPathToCachedCert (key string ) (string , bool ) {
@@ -92,66 +140,121 @@ func (c *CertCache) buildPathToCachedCert(key string) (string, bool) {
92
140
}
93
141
94
142
func (c * CertCache ) readAndValidateCertificate (key string , hosts []string , now time.Time ) (* tls.Certificate , error ) {
95
- leadingDirs , ok := c .buildPathToCachedCert (key )
143
+ leadingDir , ok := c .buildPathToCachedCert (key )
96
144
if ! ok {
97
145
return nil , nil
98
146
}
99
- path := filepath .Join (leadingDirs , certificateFileName )
100
- pemBytes , err := ioutil .ReadFile (path )
101
- if err != nil {
102
- return nil , err
147
+
148
+ if _ , err := os .Stat (leadingDir ); os .IsNotExist (err ) {
149
+ return nil , nil
103
150
}
104
- certDerBytes := []byte (nil )
105
- for {
106
- var pemBlock * pem.Block
107
- pemBlock , pemBytes = pem .Decode (pemBytes )
108
- if pemBlock == nil {
109
- break
151
+
152
+ var x509Cert * x509.Certificate
153
+ var certDerBytes [][]byte
154
+ {
155
+ certFilePath := filepath .Join (leadingDir , certificateFileName )
156
+ pemBytes , err := ioutil .ReadFile (certFilePath )
157
+ if err != nil {
158
+ return nil , err
110
159
}
111
- if pemBlock .Type == certificateBlockName {
112
- certDerBytes = pemBlock .Bytes
113
- break
160
+
161
+ for {
162
+ var pemBlock * pem.Block
163
+ pemBlock , pemBytes = pem .Decode (pemBytes )
164
+ if pemBlock == nil {
165
+ break
166
+ }
167
+ if pemBlock .Type == certificateBlockName {
168
+ certDerBytes = append (certDerBytes , pemBlock .Bytes )
169
+ }
170
+ }
171
+ if len (certDerBytes ) == 0 {
172
+ return nil , errors .Errorf ("no valid certificate contained in %s" , certFilePath )
173
+ }
174
+
175
+ x509Cert , err = x509 .ParseCertificate (certDerBytes [0 ])
176
+ if err != nil {
177
+ return nil , errors .Wrapf (err , "invalid certificate found in %s" , certFilePath )
178
+ }
179
+ if len (certDerBytes ) == 1 && c .issuerCert != nil {
180
+ err = x509Cert .CheckSignatureFrom (c .issuerCert )
181
+ if err != nil {
182
+ return nil , errors .Wrapf (err , "invalid certificate found in %s" , certFilePath )
183
+ }
184
+ }
185
+
186
+ if ! now .Before (x509Cert .NotAfter ) {
187
+ return nil , errors .Errorf ("ceritificate no longer valid (not after: %s, now: %s)" , x509Cert .NotAfter .Local ().Format (time .RFC1123 ), now .Local ().Format (time .RFC1123 ))
114
188
}
115
189
}
116
- if certDerBytes == nil {
117
- return nil , errors .Errorf ("no valid certificate contained in %s" , path )
118
- }
119
- x509Cert , err := x509 .ParseCertificate (certDerBytes )
120
- if err != nil {
121
- return nil , errors .Wrapf (err , "invalid certificate found in %s" , path )
122
- }
123
- x509Cert .RawIssuer = c .issuerCert .Raw
124
- err = x509Cert .CheckSignatureFrom (c .issuerCert )
125
- if err != nil {
126
- return nil , errors .Wrapf (err , "invalid certificate found in %s" , path )
190
+
191
+ var privKey crypto.PrivateKey
192
+ {
193
+ privKeyFilePath := filepath .Join (leadingDir , privateKeyFileName )
194
+ pemBytes , err := ioutil .ReadFile (privKeyFilePath )
195
+ if err != nil {
196
+ if ! os .IsNotExist (err ) {
197
+ return nil , err
198
+ }
199
+ }
200
+ if err == nil {
201
+ b , _ := pem .Decode (pemBytes )
202
+ privKey , err = x509 .ParsePKCS8PrivateKey (b .Bytes )
203
+ if err != nil {
204
+ return nil , errors .Wrapf (err , "failed to parse private key %s" , privKeyFilePath )
205
+ }
206
+ } else {
207
+ if c != nil {
208
+ privKey = c .privateKey
209
+ }
210
+ err = nil
211
+ }
127
212
}
128
- if ! now .Before (x509Cert .NotAfter ) {
129
- return nil , errors .Errorf ("ceritificate no longer valid (not after: %s, now: %s)" , x509Cert .NotAfter .Local ().Format (time .RFC1123 ), now .Local ().Format (time .RFC1123 ))
213
+
214
+ if privKey == nil {
215
+ return nil , errors .Errorf ("no private key is available (cache is broken)" )
130
216
}
131
217
132
218
outer:
133
219
for _ , a := range hosts {
220
+ dnsNameMatched := false
134
221
for _ , b := range x509Cert .DNSNames {
135
- if a == b {
222
+ if wildMatch (b , a ) {
223
+ dnsNameMatched = true
136
224
break outer
137
225
}
138
226
}
139
- return nil , errors .Errorf ("certificate does not cover the host name %s" , a )
227
+ if ! dnsNameMatched {
228
+ dnsNameMatched = wildMatch (x509Cert .Subject .CommonName , a )
229
+ }
230
+ if ! dnsNameMatched {
231
+ return nil , errors .Errorf ("certificate does not cover the host name %s" , a )
232
+ }
140
233
}
141
234
142
235
return & tls.Certificate {
143
- Certificate : [][] byte { certDerBytes , c . issuerCert . Raw } ,
144
- PrivateKey : c . privateKey ,
236
+ Certificate : certDerBytes ,
237
+ PrivateKey : privKey ,
145
238
}, nil
146
239
}
147
240
241
+ func (c * CertCache ) evict (key string ) error {
242
+ c .Logger .Debugf ("evicting cache foe %s" , key )
243
+ leadingDir , ok := c .buildPathToCachedCert (key )
244
+ if ! ok {
245
+ return nil
246
+ }
247
+ return os .RemoveAll (leadingDir )
248
+ }
249
+
148
250
func (c * CertCache ) readCertificate (key string , hosts []string , now time.Time ) (cert * tls.Certificate , err error ) {
149
251
cert , err = c .readAndValidateCertificate (
150
252
key ,
151
253
hosts ,
152
254
now ,
153
255
)
154
256
if err != nil {
257
+ c .evict (key )
155
258
c .Logger .Warn (err .Error ())
156
259
err = nil
157
260
}
@@ -161,20 +264,27 @@ func (c *CertCache) readCertificate(key string, hosts []string, now time.Time) (
161
264
func (c * CertCache ) Put (hosts []string , cert * tls.Certificate ) error {
162
265
key := buildKeyString (hosts )
163
266
c .certs [key ] = cert
164
- return c .writeCertificate (key , cert )
267
+ err := c .writeCertificate (key , cert )
268
+ if err != nil {
269
+ c .Logger .Warn (err .Error ())
270
+ err = nil
271
+ }
272
+ return err
165
273
}
166
274
167
275
func (c * CertCache ) Get (hosts []string , now time.Time ) (cert * tls.Certificate , err error ) {
168
276
key := buildKeyString (hosts )
169
277
cert , ok := c .certs [key ]
170
278
if ! ok {
171
- c .Logger .Debug ("Certificate not found in in-process cache" )
279
+ c .Logger .Debug ("certificate not found in in-process cache" )
172
280
cert , err = c .readCertificate (key , hosts , now )
173
281
if err != nil {
174
282
return
175
283
}
176
284
if cert != nil {
177
285
c .certs [key ] = cert
286
+ } else {
287
+ c .Logger .Debug ("certificate not found in cache directory" )
178
288
}
179
289
}
180
290
return
0 commit comments