1
1
package validation
2
2
3
3
import (
4
+ "bytes"
5
+ "crypto/ecdsa"
6
+ "crypto/rsa"
4
7
"crypto/tls"
5
8
"crypto/x509"
9
+ "encoding/pem"
6
10
"fmt"
7
11
"strings"
8
12
@@ -111,8 +115,116 @@ func ValidateRouteStatusUpdate(route *routeapi.Route, older *routeapi.Route) fie
111
115
return allErrs
112
116
}
113
117
118
+ type blockVerifierFunc func (block * pem.Block ) (* pem.Block , error )
119
+
120
+ func publicKeyBlockVerifier (block * pem.Block ) (* pem.Block , error ) {
121
+ key , err := x509 .ParsePKIXPublicKey (block .Bytes )
122
+ if err != nil {
123
+ return nil , err
124
+ }
125
+ block = & pem.Block {
126
+ Type : "PUBLIC KEY" ,
127
+ }
128
+ if block .Bytes , err = x509 .MarshalPKIXPublicKey (key ); err != nil {
129
+ return nil , err
130
+ }
131
+ return block , nil
132
+ }
133
+
134
+ func certificateBlockVerifier (block * pem.Block ) (* pem.Block , error ) {
135
+ cert , err := x509 .ParseCertificate (block .Bytes )
136
+ if err != nil {
137
+ return nil , err
138
+ }
139
+ block = & pem.Block {
140
+ Type : "CERTIFICATE" ,
141
+ Bytes : cert .Raw ,
142
+ }
143
+ return block , nil
144
+ }
145
+
146
+ func privateKeyBlockVerifier (block * pem.Block ) (* pem.Block , error ) {
147
+ key , err := x509 .ParsePKCS8PrivateKey (block .Bytes )
148
+ if err != nil {
149
+ key , err = x509 .ParsePKCS1PrivateKey (block .Bytes )
150
+ if err != nil {
151
+ key , err = x509 .ParseECPrivateKey (block .Bytes )
152
+ if err != nil {
153
+ return nil , fmt .Errorf ("block %s is not valid" , block .Type )
154
+ }
155
+ }
156
+ }
157
+ switch t := key .(type ) {
158
+ case * rsa.PrivateKey :
159
+ block = & pem.Block {
160
+ Type : "RSA PRIVATE KEY" ,
161
+ Bytes : x509 .MarshalPKCS1PrivateKey (t ),
162
+ }
163
+ case * ecdsa.PrivateKey :
164
+ block = & pem.Block {
165
+ Type : "ECDSA PRIVATE KEY" ,
166
+ }
167
+ if block .Bytes , err = x509 .MarshalECPrivateKey (t ); err != nil {
168
+ return nil , err
169
+ }
170
+ default :
171
+ return nil , fmt .Errorf ("block private key %T is not valid" , key )
172
+ }
173
+ return block , nil
174
+ }
175
+
176
+ func ignoreBlockVerifier (block * pem.Block ) (* pem.Block , error ) {
177
+ return nil , nil
178
+ }
179
+
180
+ var knownBlockDecoders = map [string ]blockVerifierFunc {
181
+ "RSA PRIVATE KEY" : privateKeyBlockVerifier ,
182
+ "ECDSA PRIVATE KEY" : privateKeyBlockVerifier ,
183
+ "PRIVATE KEY" : privateKeyBlockVerifier ,
184
+ "PUBLIC KEY" : publicKeyBlockVerifier ,
185
+ // Potential "in the wild" PEM encoded blocks that can be normalized
186
+ "RSA PUBLIC KEY" : publicKeyBlockVerifier ,
187
+ "DSA PUBLIC KEY" : publicKeyBlockVerifier ,
188
+ "ECDSA PUBLIC KEY" : publicKeyBlockVerifier ,
189
+ "CERTIFICATE" : certificateBlockVerifier ,
190
+ // Blocks that should be dropped
191
+ "EC PARAMETERS" : ignoreBlockVerifier ,
192
+ }
193
+
194
+ // sanitizePEM takes a block of data that should be encoded in PEM and returns only
195
+ // the parts of it that parse and serialize as valid recognized certs in valid PEM blocks.
196
+ // We perform this transformation to eliminate potentially incorrect / invalid PEM contents
197
+ // to prevent OpenSSL or other non Golang tools from receiving unsanitized input.
198
+ func sanitizePEM (data []byte ) ([]byte , error ) {
199
+ var block * pem.Block
200
+ buf := & bytes.Buffer {}
201
+ for len (data ) > 0 {
202
+ block , data = pem .Decode (data )
203
+ if block == nil {
204
+ return buf .Bytes (), nil
205
+ }
206
+ fn , ok := knownBlockDecoders [block .Type ]
207
+ if ! ok {
208
+ return nil , fmt .Errorf ("unrecognized PEM block %s" , block .Type )
209
+ }
210
+ newBlock , err := fn (block )
211
+ if err != nil {
212
+ return nil , err
213
+ }
214
+ if newBlock == nil {
215
+ continue
216
+ }
217
+ if err := pem .Encode (buf , newBlock ); err != nil {
218
+ return nil , err
219
+ }
220
+ }
221
+ return buf .Bytes (), nil
222
+ }
223
+
114
224
// ExtendedValidateRoute performs an extended validation on the route
115
- // including checking that the TLS config is valid.
225
+ // including checking that the TLS config is valid. It also sanitizes
226
+ // the contents of valid certificates by removing any data that
227
+ // is not recognizable PEM blocks on the incoming route.
116
228
func ExtendedValidateRoute (route * routeapi.Route ) field.ErrorList {
117
229
tlsConfig := route .Spec .TLS
118
230
result := field.ErrorList {}
@@ -142,6 +254,11 @@ func ExtendedValidateRoute(route *routeapi.Route) field.ErrorList {
142
254
for _ , cert := range certs {
143
255
certPool .AddCert (cert )
144
256
}
257
+ if data , err := sanitizePEM ([]byte (tlsConfig .CACertificate )); err != nil {
258
+ result = append (result , field .Invalid (tlsFieldPath .Child ("caCertificate" ), "redacted ca certificate data" , err .Error ()))
259
+ } else {
260
+ tlsConfig .CACertificate = string (data )
261
+ }
145
262
}
146
263
147
264
verifyOptions = & x509.VerifyOptions {
@@ -154,6 +271,12 @@ func ExtendedValidateRoute(route *routeapi.Route) field.ErrorList {
154
271
if len (tlsConfig .Certificate ) > 0 {
155
272
if _ , err := validateCertificatePEM (tlsConfig .Certificate , verifyOptions ); err != nil {
156
273
result = append (result , field .Invalid (tlsFieldPath .Child ("certificate" ), "redacted certificate data" , err .Error ()))
274
+ } else {
275
+ if data , err := sanitizePEM ([]byte (tlsConfig .Certificate )); err != nil {
276
+ result = append (result , field .Invalid (tlsFieldPath .Child ("certificate" ), "redacted certificate data" , err .Error ()))
277
+ } else {
278
+ tlsConfig .Certificate = string (data )
279
+ }
157
280
}
158
281
159
282
certKeyBytes := []byte {}
@@ -168,10 +291,24 @@ func ExtendedValidateRoute(route *routeapi.Route) field.ErrorList {
168
291
}
169
292
}
170
293
294
+ if len (tlsConfig .Key ) > 0 {
295
+ if data , err := sanitizePEM ([]byte (tlsConfig .Key )); err != nil {
296
+ result = append (result , field .Invalid (tlsFieldPath .Child ("key" ), "redacted key data" , err .Error ()))
297
+ } else {
298
+ tlsConfig .Key = string (data )
299
+ }
300
+ }
301
+
171
302
if len (tlsConfig .DestinationCACertificate ) > 0 {
172
303
if _ , err := cmdutil .CertificatesFromPEM ([]byte (tlsConfig .DestinationCACertificate )); err != nil {
173
304
errmsg := fmt .Sprintf ("failed to parse destination CA certificate: %v" , err )
174
305
result = append (result , field .Invalid (tlsFieldPath .Child ("destinationCACertificate" ), "redacted destination ca certificate data" , errmsg ))
306
+ } else {
307
+ if data , err := sanitizePEM ([]byte (tlsConfig .DestinationCACertificate )); err != nil {
308
+ result = append (result , field .Invalid (tlsFieldPath .Child ("destinationCACertificate" ), "redacted destination ca certificate data" , err .Error ()))
309
+ } else {
310
+ tlsConfig .DestinationCACertificate = string (data )
311
+ }
175
312
}
176
313
}
177
314
0 commit comments