2121import java .util .Arrays ;
2222import java .util .Collection ;
2323import java .util .HashSet ;
24+ import java .util .List ;
2425
2526import javax .net .ssl .HttpsURLConnection ;
2627import javax .net .ssl .SSLContext ;
@@ -65,7 +66,8 @@ public class SSLConfig {
6566
6667 private static /*@MonotonicNonNull*/ CipherSuiteFilterationResults CACHED_CIPHER_SUITE_FILTERATION_RESULTS ;
6768
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 ;
6971
7072 // All client ciphersuites allowed by Dropbox.
7173 //
@@ -359,8 +361,7 @@ private static void loadKeyStore(KeyStore keyStore, InputStream in)
359361
360362 Collection <X509Certificate > certs ;
361363 try {
362- certs = (Collection <X509Certificate >) x509CertFactory
363- .generateCertificates (new CommentFilterInputStream (in ));
364+ certs = deserializeCertificates (x509CertFactory , in );
364365 } catch (CertificateException ex ) {
365366 throw new LoadException ("Error loading certificate: " + ex .getMessage (), ex );
366367 }
@@ -375,87 +376,25 @@ private static void loadKeyStore(KeyStore keyStore, InputStream in)
375376 }
376377 }
377378
379+ private static List <X509Certificate > deserializeCertificates (CertificateFactory x509CertFactory , InputStream in ) throws IOException , LoadException , CertificateException {
380+ List <X509Certificate > certs = new ArrayList <X509Certificate >();
378381
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 );
424389 }
425-
426- return ord ;
390+ din . readFully ( data , 0 , length );
391+ certs . add (( X509Certificate ) x509CertFactory . generateCertificate ( new ByteArrayInputStream ( data , 0 , length ))) ;
427392 }
428393
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 );
455396 }
456397
457- private static boolean isLineFeed (int ord ) {
458- return ord == '\n' || ord == '\r' ;
459- }
398+ return certs ;
460399 }
461400}
0 commit comments