2014-07-26 107 views
5

Java 7 uygulamasının localhost'ta HTTPS isteklerini dinlemesi gerekiyor. https://localhost:8112 ve https://127.0.0.1:8112 bağlantılarını kabul etmelidir.IE, yalnızca Chrome tarafından kabul edildiğinde 127.0.0.1 için kendinden imzalı bir localhost sertifikasını reddediyor?

programlı bir otomatik olarak imzalanan X509v3 sertifika inşa Bunu yapmak için, ve aşağıdaki gibi biz Windows KÖK deposundaki bu sertifikayı yüklemiş: Bu Chrome tarafından kabul sertifikayı yapar

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

localhost erişirken öyle ise 127.0.0.1 erişirken her iki durumda da 36 (localhost ve 127.0.0.1), ancak IE 11 olarak geçerli bir sertifika tanımaz:

Test ok with Chrome (top), KO with IE (bottom)

Neden? aşağıdaki gibi sertifika sun.security.x509 paketini kullanarak, BasicConstraints, ExtendedKeyUsage ve SubjectAlternativeName uzantıları ile inşa edilmiştir: CAPI2 Tanı üzerinde this tutorial takip ederek

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; 
} 

, ben IE tarafından bildirilen hata bulduk:

<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 ve CERT_CHAIN_POLICY_STATUS üzerine dokümantasyon bana çok yardımcı olmuyor: bunun IE eski benziyor CN bir sunucu adı eşittir, ancak CN (CN=127.0.0.1) başarıyla (aynı davranış) değiştirmeye çalıştım.

+0

"CN = localhost" - Belki de değil. Bu, hem IETF hem de daha önemlisi, [CA/Browser Forums] (https://cabforum.org/baseline-requirements-documents/) tarafından onaylanmamıştır. Bölüm 9.2'ye bakınız.CA/B Temel Gereksinimlerinin 2'si: * "Onaylanmamış (Yasaklanmış, ancak yasaklanmamış)" *. CN'yi "XXX IT" gibi samimi bir hale getirin (şahsen ben yasal isimleri kullanmıyorum). Her ikisi de 'localhost' ve' 127.0.0.1' içerdiğinden, SAN iyi görünüyor. CA/B Temel Gereksinimlerinin Bölüm 9.2.1'e bakınız. – jww

+0

Son varlık sertifikalarının (sunucu veya kullanıcı sertifikaları) * Güvenilir Kök * deposuna (aslında * Güvenilen Kök Sertifika Yetkilileri * deposu olarak adlandırılır) yerleştirilmesi gerektiğine inanmıyorum. Kulağa garip geldiği için, diğer sertifikaları imzalamak için kullanılabilir. Bunun yerine, * Kişisel -> Sertifikalar *) girerler. – jww

+0

IE ve Chrome'u başlığınızda değiştirmediğinize emin misiniz? Bu bana bir Chrome ekran görüntüsüne benziyor (sertifika reddeden kişi). Emin olmak için, sertifikanızın * iPAddress * tipi 127.0.0.1 için bir SAN girişi olduğunu kontrol ettiniz mi? (Dışa aktarabilirsin ve 'openssl x509 -text ...' ile bir göz atabilirsin.) – Bruno

cevap

5

IE, IP Adres değerlerini Konu Alternatif Adı (SAN), yalnızca DNS girişlerinde desteklemez.

Bu

Microsoft'a göre, sabit olmayacak bir known limitation geçerli:

Biz sunucu adı eşleştirmek için konu diğer adı IP seçim kullanarak desteklemez. IP adresini bir DNS adı seçimi için bir dize olarak ekleyerek bu konuda çalışabilirsiniz. Şu anda bu sorunu düzeltmeyi planlamıyoruz.

"dns:127.0.0.1" 

Maalesef bu keytool veya programlı çünkü Java bug 8016345 ait sun.security.x509 sınıfları ile kullanarak mümkün değildir:

Yani idare doğru yolu IP adresini içeren bir DNS girdisini eklemektir. Kullanıcıların gönderme 127.0.0.1 kullandığınızda

//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"); 
+0

Belki de BouncyCastle veya [OpenSSL ("IP" yerine "DNS" yerine))] (http://stackoverflow.com/a/8444863/372643) ile deneyebilirsiniz. (Özel API'yi güneşten kullanma. * 'Genellikle iyi bir fikir değildir, ama bu size kalmış.) – Bruno

+0

Teşekkürler, ancak COTS kullanımımızı en düşük düzeyde tutmaya çalışıyoruz. Oracle JRE ve OpenJDK/IcedTea'nın desteklenen sürümleriyle çalıştığı sürece bu paketi kullanmak bizim için iyi. – vip

+0

Sanırım sertifika oluşturmayı uygulamanıza entegre etmeye çalışmak yerine, bir "localhost" sertifikası ve bununla önceden oluşturduğunuz özel anahtarını gönderebilirsiniz. Tabii ki, genel olarak özel anahtar materyaller asla paylaşılmamalı, ancak bu durumda tüm kullanıcılar arasında bir sertifika ve özel anahtarın '127.0.0.1' ile paylaşılması muhtemelen büyük bir risk taşımamaktadır çünkü onlar da paylaşmak zorundadırlar. Yine aynı makine. – Bruno

-1

Neden sadece bir HTTP 301 yönlendirmesi sorunu:

Sadece DNSName.java son sürümünü kopyalayarak, kendiniz bu hatayı düzeltmek ve bu çeki kaldırmak için ancak mümkündür Bunun yerine localhost'a mı?

+0

Yeniden yönlendirmeler yalnızca ** sonra ** ilk istek/yanıt değişimi başarıyla gerçekleştirilmiştir. Sertifika ilk istek için geçersiz ise herhangi bir yanıt almayacaksınız. – Bruno

İlgili konular