通过HttpClient密钥/信任存储进行Dropwizard客户端证书身份验证

时间:2016-01-20 19:35:46

标签: java ssl ssl-certificate apache-httpclient-4.x dropwizard

我正在运行一个dropwizard服务器,以及一个利用Apache HttpClient 4.5.1的客户端。

给定一个包含公钥和私钥的.pfx文件,如何在服务器和客户端上构建我的密钥/信任存储以接受/信任并传递证书进行身份验证目的

我遇到的是客户端信任提供的服务器证书,但是 在包含每个tls规范的证书请求的服务器hello之后,我的客户端无法找到要发回的合适证书。

我的第一个想法是将密钥库和信任库作为相同的pfx文件运行服务器,但是当将pfx文件作为服务器中的信任存储加载时,java会抛出空的证书链错误。所以我必须手动创建一个信任存储区。

以下是我认为可以让整个过程成功的一般步骤:

  1. 使用带有PKCS12密钥库类型的.pfx文件运行服务器。
  2. 从pfx文件中提取证书,并使用证书创建一个Java信任库。
  3. 使用上述clientCerts.jks文件作为信任存储
  4. 运行服务器
  5. 使用设置为clientCerts.jks文件的密钥库运行客户端
  6. 使用设置为.pfx PKCS12密钥库的信任库运行客户端。
  7. 这些步骤不起作用,我尝试过其他不太明显的排列,但没有一个能够奏效。我接近这个的方式有什么明显的错误吗?有没有人对实际让它起作用有任何建议?

    下面有很多细节(包括ssl调试日志)

    PFX证书信息: (它是一个有效的公司签名证书,但我不会在任何地方将根CA视为可信任,这就是为什么我只创建一个信任存储,以便我可以信任客户端证书)。

    $ openssl pkcs12 -info -in cert.pfx
    Enter Import Password:
    MAC Iteration 1
    MAC verified OK
    PKCS7 Data
    Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2000
    Bag Attributes
        Microsoft Local Key set: <No Values>
        localKeyID: 01 00 00 00
        friendlyName: xxx
        Microsoft CSP Name: Microsoft RSA SChannel Cryptographic Provider
    Key Attributes
        X509v3 Key Usage: 10
    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:
    -----BEGIN ENCRYPTED PRIVATE KEY-----
    xxx
    -----END ENCRYPTED PRIVATE KEY-----
    PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2000
    Certificate bag
    Bag Attributes
        localKeyID: 01 00 00 00
        friendlyName: my.domain.com
    subject=/C=US/O=My Company/OU=Web Servers/CN=my.domain.com
    issuer=/C=US/O=My Company
    -----BEGIN CERTIFICATE-----
    xxx
    -----END CERTIFICATE-----
    

    Java Trust store Creation:

    //create pem file
    openssl pkcs12 -in cert.pfx -out tempCert.crt -nokeys -clcerts
    
    //convert to x509
    openssl x509 -inform pem -in tempCert.crt -outform der -out tempx509Cert.cer
    
    //create a java trust store
    keytool -import -file tempx509Cert.cer -alias firstCA -keystore newJavaTrustStore.jks
    

    Dropwizard配置:

    applicationConnectors:
        - type: https
          port: 443
          bindHost: localhost 
          keyStorePath: ./cert.pfx
          keyStorePassword: pw
          keyStoreType: PKCS12
          trustStorePath: ./clientCerts.jks
          trustStorePassword: pw
          trustStoreType: JKS
          supportedProtocols: [TLSv1, TLSv1.1, TLSv1.2]
          excludedProtocols: [SSLv2Hello, SSLv3]
          validateCerts: false
          needClientAuth: true
          wantClientAuth: true
    

    HttpClient配置值:

    keyStorePath: ./clientCerts.jks
    keyStorePassword: pw
    keyStoreType: JKS   
    trustStorePath: ./cert.pfx
    trustStorePassword: pw
    trustStoreType: PKCS12
    

    HttpClient配置:

    public static CloseableHttpClient getSecurePooledHttpClient(
            final String host,
            final int port,
            final boolean ssl,
            final String keystorePath,
            final String keystorePassword,
            final String keystoreType,
            final String trustStorePath,
            final String trustStorePassword,
            final String trustStoreType
    
    
    
    ) throws Exception {
    
        //Setup the keystore that will hold the client certificate
        KeyStore ks = KeyStore.getInstance(keystoreType);
        ks.load(new FileInputStream(new File(keystorePath)),
                keystorePassword.toCharArray());
    
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, keystorePassword.toCharArray());
    
        //Setup the Trust Store so we know what certificates 
        //we can trust that are hosting the service
        KeyStore ts = KeyStore.getInstance((trustStoreType));
        ts.load(new FileInputStream(new File(trustStorePath)), 
                trustStorePassword.toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(ts);
    
    
        //setup our SSL context to be TLSv1.2, then setup the key and trust manager.
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    
    
    
        //Register the socket factory so that it uses the ssl Context and key
        // manager we created above
        Registry<ConnectionSocketFactory> socketFactoryRegistry = 
                RegistryBuilder.<ConnectionSocketFactory>create()
                .register("https", new SSLConnectionSocketFactory(sslContext, 
                        NoopHostnameVerifier.INSTANCE))
                .build();
    
        //Define an overridden routeplanner that setups up our default host 
        // so all our later calls can simply be
        //sub-routes.
        HttpRoutePlanner routePlanner = 
                new DefaultRoutePlanner(DefaultSchemePortResolver.INSTANCE)
        {
            @Override
            public HttpRoute determineRoute(
                    final HttpHost target,
                    final HttpRequest request,
                    final HttpContext context) throws HttpException {
                return super.determineRoute(
                        target != null ? target : new HttpHost(host, port, ssl ? "https" : "http"),
                        request, context);
            }
        };
        return BuildClientWithRoutePlanner(socketFactoryRegistry, routePlanner);
    

    客户端SSL调试:

    ...

    *** ServerHello, TLSv1.2
    RandomCookie:  Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    Compression Method: 0
    Extension renegotiation_info, renegotiated_connection: <empty>
    ***
    %% Initialized:  [Session-7, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256]
    ** TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    *** Certificate chain
    chain [0] = [
    [
      Version: V3
      Subject: CN=my.domain.com, OU=Web Servers, O=My Company, C=US
      Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
    

    .........

    ***
    Found trusted certificate:
    [
    [
      Version: V3
      Subject: CN=my.domain.com, OU=Web Servers, O=My Company, C=US
      Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
    
      Key:  Sun RSA public key, 2048 bits
    

    ...

    *** CertificateRequest
    Cert Types: RSA, DSS, ECDSA
    Supported Signature Algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
    Cert Authorities:
    <CN=my.domain.com, OU=Web Servers, O=My Company, C=US>
    *** ServerHelloDone
    Warning: no suitable certificate found - continuing without client authentication
    *** Certificate chain
    <Empty>
    ***
    

0 个答案:

没有答案
相关问题