Как отключить проверку критического расширения ssl в Android?

#android #ssl #bouncycastle #okhttp

#Android #ssl #bouncycastle #okhttp

Вопрос:

Я использую OkHttp для отправки HTTPS-запросов на сервер в моем приложении для Android. Это нормально с версией Android> Jelly Bean, но следующее исключение выдается с помощью Jelly Bean :

 javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Certificate has unsupported critical extension
10-04 12:45:01.391 7570-7735/mop.orange.com.moplibapptest5 I/System.out:     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
10-04 12:45:01.391 7570-7735/mop.orange.com.moplibapptest5 I/System.out:     at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:241)
  

Похоже, это связано с сертификатом сервера SSL / TLS, который содержит 2 расширения с тегом «критический». Я не могу изменить этот сертификат, потому что сервер не мой.

Я попытался включить / отключить поддержку расширений TLS, но поведение такое же: (

 ConnectionSpec connSpec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
     .supportsTlsExtensions(false)
     .build();

OkHttpClient.Builder()
    .connectionSpecs(Collections.singletonList(connSpec))
  

Знаете ли вы, как я могу отключить проверку критического расширения в OkHttp (или в Bouncy Castle, который, кажется, находится под), пожалуйста?

Ответ №1:

Я использую способ OkHttp для настройки доверенных сертификатов, затем я оборачиваю TrustManager и сертификат, чтобы вернуть пустой список критических расширений.

Вот перенос TrustManager, когда это класс Jelly Bean :

         if(trustManagers[0].getClass().toString().equals("class org.apache.harmony.xnet.provider.jsse.TrustManagerImpl")) {
            logger.debug("Wrapping TrustManager to return no critical extension");
            return new TrustManagerNoCritical((X509TrustManager) trustManagers[0]);
        }
  

Вот класс переноса TrustManager для переноса сертификатов в цепочку :

 public class TrustManagerNoCritical implements X509TrustManager  {

protected X509TrustManager trustManager;

public TrustManagerNoCritical(X509TrustManager realTrustManager) {
    trustManager = realTrustManager;
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    trustManager.checkClientTrusted(chain, authType);
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

    List<X509Certificate> certifs = new ArrayList<X509Certificate>();       

    for (X509Certificate certif : chain) {
        certifs.add(new CertificateNoCritical(certif));
    }

    X509Certificate[] newChain = new X509Certificate[certifs.size()];  
    newChain = certifs.toArray(newChain);

    trustManager.checkServerTrusted(newChain, authType);
}

@Override
public X509Certificate[] getAcceptedIssuers() {
    return trustManager.getAcceptedIssuers();
}

}
  

Вот класс сертификата, который переносит реальный сертификат и не возвращает критическое расширение :

 public class CertificateNoCritical extends X509Certificate {

protected X509Certificate certif;

public CertificateNoCritical(X509Certificate certificateToWrap) {
    certif = certificateToWrap;
}


@Override
public boolean hasUnsupportedCriticalExtension() {
    return certif.hasUnsupportedCriticalExtension();
}

@Override
public Set<String> getCriticalExtensionOIDs() {     
    // Return empty Set to avoid "critical extension" Exception
    return new HashSet<String>();       
}

@Override
public Set<String> getNonCriticalExtensionOIDs() {
    return certif.getNonCriticalExtensionOIDs();
}

@Override
public byte[] getExtensionValue(String oid) {
    return certif.getExtensionValue(oid);
}

@Override
public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
    certif.checkValidity();
}

@Override
public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
    certif.checkValidity(date);
}

@Override
public int getVersion() {
    return certif.getVersion();
}

@Override
public BigInteger getSerialNumber() {
    return certif.getSerialNumber();
}

@Override
public Principal getIssuerDN() {
    return certif.getIssuerDN();
}

@Override
public Principal getSubjectDN() {
    return certif.getSubjectDN();
}

@Override
public Date getNotBefore() {
    return certif.getNotBefore();
}

@Override
public Date getNotAfter() {
    return certif.getNotAfter();
}

@Override
public byte[] getTBSCertificate() throws CertificateEncodingException {
    return certif.getTBSCertificate();
}

@Override
public byte[] getSignature() {
    return certif.getSignature();
}

@Override
public String getSigAlgName() {
    return certif.getSigAlgName();
}

@Override
public String getSigAlgOID() {
    return certif.getSigAlgOID();
}

@Override
public byte[] getSigAlgParams() {
    return certif.getSigAlgParams();
}

@Override
public boolean[] getIssuerUniqueID() {
    return certif.getIssuerUniqueID();
}

@Override
public boolean[] getSubjectUniqueID() {
    return certif.getSubjectUniqueID();
}

@Override
public boolean[] getKeyUsage() {
    return certif.getKeyUsage();
}

@Override
public int getBasicConstraints() {
    return certif.getBasicConstraints();
}

@Override
public byte[] getEncoded() throws CertificateEncodingException {
    return certif.getEncoded();
}

@Override
public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
        NoSuchProviderException, SignatureException {
    certif.verify(key);
}

@Override
public void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException,
        InvalidKeyException, NoSuchProviderException, SignatureException {
    certif.verify(key, sigProvider);
}

@Override
public String toString() {
    return certif.toString();
}

@Override
public PublicKey getPublicKey() {
    return certif.getPublicKey();
}

}