当Chrome接受它时,为什么IE仅拒绝127.0.0.1的自签名本地主机证书? [英] Why IE rejects a self-signed localhost certificate for 127.0.0.1 only, when Chrome accepts it?

查看:221
本文介绍了当Chrome接受它时,为什么IE仅拒绝127.0.0.1的自签名本地主机证书?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的Java 7应用程序需要在localhost上侦听HTTPS请求。它必须接受 https:// localhost:8112 https://127.0.0.1:8112 的连接。

Our Java 7 application needs to listen for HTTPS requests on localhost. It must accept connections on https://localhost:8112 and https://127.0.0.1:8112.

为此,我们以编程方式构建了自动签名的X509v3证书,并且我们已在 Windows-ROOT 密钥库中安装此证书,如下所示:

To do so we have programmatically built an auto-signed X509v3 certificate, and we have installed this certificate in the Windows-ROOT keystore, as follows:

KeyStore.TrustedCertificateEntry trustedCert = ...;
KeyStore ks = KeyStore.getInstance("Windows-ROOT");
ks.load(null, null);
ks.setEntry("xxxx_localhost", trustedCert, null);

这使得Chrome 36在两种情况下都接受了证书(localhost和127.0.0.1),但IE在访问 127.0.0.1 时访问 localhost 时,11无法将证书识别为有效:

This makes the certificate accepted by Chrome 36 in both cases (localhost and 127.0.0.1), but IE 11 does not recognize the certificate as valid when accessing 127.0.0.1 while it does when accessing localhost:

为什么?通过 BasicConstraints ExtendedKeyUsage SubjectAlternativeName 扩展,使用 sun.security.x509构建证书,如下所示。 package:

Why? The certificate is built as follows, with BasicConstraints, ExtendedKeyUsage and SubjectAlternativeName extensions, by using the sun.security.x509 package:

KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
KeyPair kp = generator.generateKeyPair();

X509Certificate cert = generateCertificate("CN=localhost, OU=XXX, O=XXX", kp,
    1825, "SHA256withRSA", "ip:127.0.0.1,dns:localhost,uri:https://127.0.0.1:8112");

/**
 * Create a self-signed X.509 Certificate.
 * @param dn the X.509 Distinguished Name
 * @param pair the KeyPair
 * @param days how many days from now the Certificate is valid for
 * @param algorithm the signing algorithm, eg "SHA256withRSA"
 * @param san SubjectAlternativeName extension (optional)
 */
private static X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm, String san) 
    throws GeneralSecurityException, IOException {
    PrivateKey privkey = pair.getPrivate();
    X509CertInfo info = new X509CertInfo();
    Date from = new Date();
    Date to = new Date(from.getTime() + days * 86400000l);
    CertificateValidity interval = new CertificateValidity(from, to);
    BigInteger sn = new BigInteger(64, new SecureRandom());
    X500Name owner = new X500Name(dn);

    info.set(X509CertInfo.VALIDITY, interval);
    info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
    info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
    info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
    info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
    info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
    AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
    info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

    CertificateExtensions ext = new CertificateExtensions();
    // Critical: Not CA, max path len 0
    ext.set(BasicConstraintsExtension.NAME, new BasicConstraintsExtension(true, false, 0));
    // Critical: only allow TLS ("serverAuth" = 1.3.6.1.5.5.7.3.1)
    ext.set(ExtendedKeyUsageExtension.NAME, new ExtendedKeyUsageExtension(true,
            new Vector<ObjectIdentifier>(Arrays.asList(new ObjectIdentifier("1.3.6.1.5.5.7.3.1")))));

    if (san != null) {
        int colonpos;
        String[] ps = san.split(",");
        GeneralNames gnames = new GeneralNames();
        for(String item: ps) {
            colonpos = item.indexOf(':');
            if (colonpos < 0) {
                throw new IllegalArgumentException("Illegal item " + item + " in " + san);
            }
            String t = item.substring(0, colonpos);
            String v = item.substring(colonpos+1);
            gnames.add(createGeneralName(t, v));
        }
        // Non critical
        ext.set(SubjectAlternativeNameExtension.NAME, new SubjectAlternativeNameExtension(false, gnames));
    }

    info.set(X509CertInfo.EXTENSIONS, ext);

    // Sign the cert to identify the algorithm that's used.
    X509CertImpl cert = new X509CertImpl(info);
    cert.sign(privkey, algorithm);

    // Update the algorithm, and resign.
    algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG);
    info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
    cert = new X509CertImpl(info);
    cert.sign(privkey, algorithm);
    return cert;
}

通过关注本教程,我发现了IE报告的错误:

By following this tutorial on CAPI2 Diagnostics, I have found the error reported by IE:

<CertVerifyCertificateChainPolicy>
    <Policy type="CERT_CHAIN_POLICY_SSL" constant="4" /> 
    <Certificate fileRef="XXX.cer" subjectName="127.0.0.1" /> 
    <CertificateChain chainRef="{XXX}" /> 
    <Flags value="0" /> 
    <SSLAdditionalPolicyInfo authType="server" serverName="127.0.0.1">
        <IgnoreFlags value="0" /> 
    </SSLAdditionalPolicyInfo>
    <Status chainIndex="0" elementIndex="0" /> 
    <EventAuxInfo ProcessName="iexplore.exe" /> 
    <CorrelationAuxInfo TaskId="{XXX}" SeqNumber="4" /> 
    <Result value="800B010F">The certificate's CN name does not match the passed value.</Result> 
</CertVerifyCertificateChainPolicy>

CertVerifyCertificateChainPolicy CERT_CHAIN_POLICY_STATUS 对我没有多大帮助:看起来IE期望CN等于服务器名称,但我我试图将我的CN更改为 CN = 127.0.0.1 但没有成功(相同的行为)。

The documentation on CertVerifyCertificateChainPolicy and CERT_CHAIN_POLICY_STATUS doesn't help me much: it looks like IE expects a CN equal to server name, but I have tried to change my CN to CN=127.0.0.1 without success (same behaviour).

推荐答案

IE不支持主题备用名称(SAN)中的IP地址值,仅支持DNS条目。

IE does not support IP addresses values in Subject Alternative Name (SAN), only DNS entries.

这是已知的限制赢了根据微软的说法,我们不会修复:

This is a known limitation that won't be fixed, according to Microsoft:


我们不支持使用Subject Altern中的IP选项用于匹配服务器名称的名称。您可以通过将IP地址添加为DNS名称选择的字符串来解决此问题。目前我们还没有计划解决这个问题。

We do not support using the IP choice in the Subject Alternative name to match the server name. You can work around this by adding the IP address as a string for a DNS name choice. At this time we do not plan on fixing this issue.

所以处理它的正确方法是添加一个包含IP地址:

So the correct way to handle it is to add a DNS entry containing the IP address:

"dns:127.0.0.1"

不幸的是,这不可能使用 keytool 或以编程方式使用 sun.security.x509 类因为 Java bug 8016345

Unfortunately, this is not possible using keytool or programmatically with sun.security.x509 classes because of Java bug 8016345.

It然而,只要复制最新版本的 DNSName.java 并删除此项检查:

It is however possible to fix this bug by yourself, just by copying the latest version of DNSName.java and remove this check:

//DNSName components must begin with a letter A-Z or a-z
if (alpha.indexOf(name.charAt(startIndex)) < 0)
    throw new IOException("DNSName components must begin with a letter");

这篇关于当Chrome接受它时,为什么IE仅拒绝127.0.0.1的自签名本地主机证书?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆