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
6667private 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
360362Collection <X509Certificate >certs ;
361363try {
362- certs = (Collection <X509Certificate >)x509CertFactory
363- .generateCertificates (new CommentFilterInputStream (in ));
364+ certs =deserializeCertificates (x509CertFactory ,in );
364365 }catch (CertificateException ex ) {
365366throw 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}