21
21
import java .util .Arrays ;
22
22
import java .util .Collection ;
23
23
import java .util .HashSet ;
24
+ import java .util .List ;
24
25
25
26
import javax .net .ssl .HttpsURLConnection ;
26
27
import javax .net .ssl .SSLContext ;
@@ -65,7 +66,8 @@ public class SSLConfig {
65
66
66
67
private static /*@MonotonicNonNull*/ CipherSuiteFilterationResults CACHED_CIPHER_SUITE_FILTERATION_RESULTS ;
67
68
68
- private static final String ROOT_CERTS_RESOURCE = "/trusted-certs.crt" ;
69
+ private static final String ROOT_CERTS_RESOURCE = "/trusted-certs.raw" ;
70
+ private static final int MAX_CERT_LENGTH = 10 * 1024 ;
69
71
70
72
// All client ciphersuites allowed by Dropbox.
71
73
//
@@ -359,8 +361,7 @@ private static void loadKeyStore(KeyStore keyStore, InputStream in)
359
361
360
362
Collection <X509Certificate > certs ;
361
363
try {
362
- certs = (Collection <X509Certificate >) x509CertFactory
363
- .generateCertificates (new CommentFilterInputStream (in ));
364
+ certs = deserializeCertificates (x509CertFactory , in );
364
365
} catch (CertificateException ex ) {
365
366
throw new LoadException ("Error loading certificate: " + ex .getMessage (), ex );
366
367
}
@@ -375,87 +376,25 @@ private static void loadKeyStore(KeyStore keyStore, InputStream in)
375
376
}
376
377
}
377
378
379
+ private static List <X509Certificate > deserializeCertificates (CertificateFactory x509CertFactory , InputStream in ) throws IOException , LoadException , CertificateException {
380
+ List <X509Certificate > certs = new ArrayList <X509Certificate >();
378
381
379
- /**
380
- * Strips '#' comments from PEM encoded cert file. Java 7+ handles skipping comments that aren't
381
- * within certificate blocks. Java 6, however, will fail to parse the cert file if it contains
382
- * anything other than certificate blocks.
383
- *
384
- * <p><b> NOTE: Android will incorrectly parse PEM encoded files containing comments.</b> When
385
- * comments are left in the file, some of the certificates may not be loaded properly. This
386
- * results in exceptions like the one below:
387
- *
388
- * <pre>
389
- * Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
390
- * at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:328)
391
- * at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:103)
392
- * at com.android.okhttp.Connection.connect(Connection.java:143)
393
- * ...
394
- * </pre>
395
- */
396
- private static final class CommentFilterInputStream extends FilterInputStream {
397
- private boolean isLineStart ;
398
-
399
- public CommentFilterInputStream (InputStream in ) {
400
- super (in );
401
- this .isLineStart = true ;
402
- }
403
-
404
- @ Override
405
- public int read () throws IOException {
406
- int ord = super .read ();
407
-
408
- // only filter at start of line
409
- if (!isLineStart ) {
410
- return ord ;
411
- }
412
-
413
- while (ord == '#' ) {
414
- // chomp the comment
415
- do {
416
- ord = super .read ();
417
- } while (!isLineFeed (ord ) && ord != -1 );
418
-
419
- // now chomp the line feeds
420
- while (isLineFeed (ord ) && ord != -1 ) {
421
- ord = super .read ();
422
- }
423
- isLineStart = true ;
382
+ DataInputStream din = new DataInputStream (in );
383
+ byte [] data = new byte [MAX_CERT_LENGTH ];
384
+ while (true ) {
385
+ int length = din .readUnsignedShort ();
386
+ if (length == 0 ) break ;
387
+ if (length > MAX_CERT_LENGTH ) {
388
+ throw new LoadException ("Invalid length for certificate entry: " + length , null );
424
389
}
425
-
426
- return ord ;
390
+ din . readFully ( data , 0 , length );
391
+ certs . add (( X509Certificate ) x509CertFactory . generateCertificate ( new ByteArrayInputStream ( data , 0 , length ))) ;
427
392
}
428
393
429
- @ Override
430
- public int read (byte [] b ) throws IOException {
431
- return read (b , 0 , b .length );
432
- }
433
-
434
- @ Override
435
- public int read (byte [] b , int off , int len ) throws IOException {
436
- if (b == null ) {
437
- throw new NullPointerException ("b" );
438
- }
439
- if (off < 0 || len < 0 || len > (b .length - off )) {
440
- throw new IndexOutOfBoundsException ();
441
- }
442
-
443
- int count = 0 ;
444
- for (int i = 0 ; i < len ; ++i ) {
445
- int ord = read ();
446
- if (ord == -1 ) {
447
- break ;
448
- }
449
-
450
- b [off + i ] = (byte ) ord ;
451
- ++count ;
452
- }
453
-
454
- return count == 0 ? -1 : count ;
394
+ if (din .read () >= 0 ) {
395
+ throw new LoadException ("Found data after after zero-length header." , null );
455
396
}
456
397
457
- private static boolean isLineFeed (int ord ) {
458
- return ord == '\n' || ord == '\r' ;
459
- }
398
+ return certs ;
460
399
}
461
400
}
0 commit comments