Por que o Java não envia o certificado do cliente durante o handshake SSL?

Estou tentando me conectar a um serviço seguro na web.

Eu estava recebendo uma falha de handshake mesmo que meu keystore e truststore tenham sido configurados corretamente.

Depois de vários dias de frustração, interminável googling e perguntando a todos, descobri que o único problema era que o java escolheu não enviar o certificado do cliente para o servidor durante o handshake.

Especificamente:

  1. Servidor solicitou um certificado de cliente (CN = RootCA) – ou seja, “me dê um certificado assinado pela CA raiz”
  2. Java olhou para o keystore e só encontrou o meu certificado de cliente que é assinado pelo “SubCA”, que por sua vez é emitido pelo “RootCA”. Não se incomodou em olhar para o truststore … duh OK eu acho
  3. Infelizmente, quando tentei adicionar o certificado “SubCA” ao keystore, isso não ajudou em nada. Eu verifiquei se os certificados são carregados no keystore. Eles fazem, mas o KeyManager ignora todos os certificados, exceto o cliente.
  4. Todos os itens acima levam ao fato de que o java decide que não possui nenhum certificado que atenda ao pedido do servidor e não envia nada … tadaaa falha de handshake 🙁

Minhas perguntas:

  1. É possível que eu adicionei o certificado “SubCA” ao keystore de uma maneira que “quebrou a cadeia de certificados” ou algo assim para que o KeyManager apenas carregue o certificado de cliente e ignore o resto? (Chrome e openssl conseguem descobrir isso, então por que não pode java? – Observe que o certificado “SubCA” é sempre apresentado separadamente como a autoridade confiável, então o Chrome aparentemente o empacota corretamente junto com o certificado do cliente durante o handshake)
  2. Isso é um “problema de configuração” formal no lado do servidor? O servidor é um terceiro. Eu esperaria que o servidor solicitasse um certificado assinado pela autoridade “SubCA”, já que foi isso que eles nos forneceram. Eu suspeito que o fato de que isso funciona no Chrome e openssl é porque eles são “menos restritivas” e java só vai “pelo livro” e falhar.

Consegui montar uma solução suja para isso, mas não estou muito feliz com isso, então ficarei feliz se alguém puder esclarecer isso para mim.

É possível que você tenha importado o certificado de CA intermediária para o keystore sem associá-lo à input em que você possui seu certificado de cliente e sua chave privada. Você deve poder ver isso usando keytool -v -list -keystore store.jks . Se você obtiver apenas um certificado por input de alias, eles não estarão juntos.

Você precisaria importar seu certificado e sua cadeia juntos para o alias de keystore que possui sua chave privada.

Para descobrir qual alias de keystore tem a chave privada, use keytool -list -keystore store.jks (estou assumindo o tipo de loja JKS aqui). Isto lhe dirá algo como isto:

 Your keystore contains 1 entry myalias, Feb 15, 2012, PrivateKeyEntry, Certificate fingerprint (MD5): xxxxxxxx 

Aqui, o alias é myalias . Se você usar -v além disso, deverá ver o Alias Name: myalias .

Se você não tiver isso separadamente, exporte seu certificado de cliente do keystore:

 keytool -exportcert -rfc -file clientcert.pem -keystore store.jks -alias myalias 

Isso deve fornecer um arquivo PEM.

Usando um editor de texto (ou cat ), prepare o arquivo (vamos chamá-lo bundle.pem ) com esse certificado de cliente e o certificado de CA intermediário (e possivelmente o certificado de CA raiz se desejar), para que o certificado de cliente esteja no início e seu certificado de emissor está abaixo.

Isso deve parecer com:

 -----BEGIN CERTIFICATE----- MIICajCCAdOgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJVSzEa .... -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICkjCCAfugAwIBAgIJAKm5bDEMxZd7MA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV .... -----END CERTIFICATE----- 

Agora, importe este pacote novamente para o alias onde sua chave privada é:

 keytool -importcert -keystore store.jks -alias myalias -file bundle.pem 

Como um add aqui, você pode usar %> openssl s_client -connect host.example.com:443 e ver o dump e verificar se todo o certificado principal é válido contra o cliente. Você está procurando por isso na parte inferior da saída. Verifique o código de retorno: 0 (ok)

Se você adicionar -showcerts, ele despejará todas as informações do keychain que foi enviado junto com o certificado do host, que é o que você carregou no seu keychain.

    Intereting Posts