如何禁用Android中的ssl critical extension extension check?

时间:2016-10-07 08:01:58

标签: android ssl bouncycastle okhttp

我使用okHTTP将HTTPS请求发送到我的Android应用程序中的服务器。适用于Android版本>果冻豆,但果冻豆引发了以下异常:

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 Extensions支持,但行为是相同的:(

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

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

你知道我怎么能在okHTTP(或似乎在下面的Bouncy Castle)中禁用关键扩展检查?

1 个答案:

答案 0 :(得分:2)

我使用okHTTP waycustomize可信证书,然后我将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();
}

}