Sou relativamente novo HTTPS/SSL/TLS
e estou um pouco confuso sobre o que exatamente os clientes devem apresentar ao se autenticar com certificados.
Estou escrevendo um cliente Java que precisa fazer um simples POST
dado para um determinado URL
. Essa parte funciona bem, o único problema é que deve ser resolvida HTTPS
. A HTTPS
parte é bastante fácil de manusear (com HTTPclient
ou usando o HTTPS
suporte interno do Java ), mas estou preso na autenticação com certificados de cliente. Percebi que já existe uma pergunta muito semelhante aqui, que ainda não testei com o meu código (o fará em breve). Meu problema atual é que - o que quer que eu faça - o cliente Java nunca envia o certificado (posso verificar isso com PCAP
despejos).
Gostaria de saber o que exatamente o cliente deve apresentar ao servidor ao se autenticar com certificados (especificamente para Java - se isso realmente importa)? Isso é um JKS
arquivo ou PKCS#12
? O que deveria estar neles; apenas o certificado do cliente ou uma chave? Se sim, qual chave? Há um pouco de confusão sobre todos os diferentes tipos de arquivos, tipos de certificado e outros.
Como eu disse antes, sou iniciante HTTPS/SSL/TLS
e gostaria de receber algumas informações básicas (não precisa ser um ensaio; vou aceitar links para bons artigos).
fonte
Respostas:
Finalmente consegui resolver todos os problemas, então vou responder minha própria pergunta. Essas são as configurações / arquivos que eu usei para gerenciar para resolver meus problemas específicos;
O keystore do cliente é um arquivo no formato PKCS # 12 que contém
Para gerá-lo, usei o
pkcs12
comando do OpenSSL , por exemplo;Dica: certifique-se de obter o OpenSSL mais recente, não a versão 0.9.8h, porque isso parece sofrer de um bug que não permite gerar corretamente arquivos PKCS # 12.
Esse arquivo PKCS # 12 será usado pelo cliente Java para apresentar o certificado do cliente ao servidor quando o servidor solicitar explicitamente a autenticação do cliente. Consulte o artigo da Wikipedia sobre TLS para obter uma visão geral de como o protocolo para autenticação de certificado de cliente realmente funciona (também explica por que precisamos da chave privada do cliente aqui).
O armazenamento confiável do cliente é um arquivo de formato JKS direto que contém os certificados CA raiz ou intermediários . Esses certificados de autoridade de certificação determinarão com quais pontos de extremidade você poderá se comunicar; nesse caso, permitirá que seu cliente se conecte a qualquer servidor que apresente um certificado que foi assinado por uma das autoridades de certificação do armazenamento confiável.
Para gerá-lo, você pode usar a ferramenta chave do Java padrão, por exemplo;
Usando esse armazenamento confiável, seu cliente tentará executar um handshake SSL completo com todos os servidores que apresentarem um certificado assinado pela CA identificado por
myca.crt
.Os arquivos acima são estritamente apenas para o cliente. Quando você também deseja configurar um servidor, ele precisa de seus próprios arquivos de armazenamento de chaves e de confiança. Um ótimo passo a passo para configurar um exemplo completo de trabalho para um cliente e servidor Java (usando o Tomcat) pode ser encontrado neste site .
Questões / Comentários / Dicas
-Djavax.net.debug=ssl
mas é mais estruturado e (sem dúvida) mais fácil de interpretar se você não se sentir confortável com a saída de depuração SSL do Java.É perfeitamente possível usar a biblioteca httpclient Apache. Se você deseja usar o httpclient, substitua o URL de destino pelo equivalente HTTPS e adicione os seguintes argumentos da JVM (que são iguais para qualquer outro cliente, independentemente da biblioteca que você deseja usar para enviar / receber dados por HTTP / HTTPS) :
fonte
SSLContext
que está na resposta de @ Magnus.Outras respostas mostram como configurar globalmente certificados de cliente. No entanto, se você desejar definir programaticamente a chave do cliente para uma conexão específica, em vez de defini-la globalmente em todos os aplicativos em execução na sua JVM, poderá configurar seu próprio SSLContext da seguinte maneira:
fonte
sslContext = SSLContexts.custom().loadTrustMaterial(keyFile, PASSWORD).build();
. Não consegui trabalhar com issoloadKeyMaterial(...)
.loadKeyMaterial(keystore, keyPassphrase.toCharArray())
código 'também!SSLContext
.O arquivo JKS é apenas um contêiner para certificados e pares de chaves. Em um cenário de autenticação do lado do cliente, as várias partes das chaves estarão localizadas aqui:
A separação do armazenamento confiável e keystore não é obrigatória, mas recomendada. Eles podem ser o mesmo arquivo físico.
Para definir os locais do sistema de arquivos dos dois armazenamentos, use as seguintes propriedades do sistema:
e no servidor:
Para exportar o certificado do cliente (chave pública) para um arquivo, para copiá-lo para o servidor, use
Para importar a chave pública do cliente para o keystore do servidor, use (como o pôster mencionado, isso já foi feito pelos administradores do servidor)
fonte
Maven pom.xml:
Código Java:
fonte
configureRequest()
para definir o proxy do projeto do cliente, certo?Para aqueles que simplesmente desejam configurar uma autenticação bidirecional (certificados de servidor e cliente), uma combinação desses dois links o levará até lá:
Configuração de autenticação bidirecional:
https://linuxconfig.org/apache-web-server-ssl-authentication
Você não precisa usar o arquivo de configuração openssl que eles mencionam; Apenas use
$ openssl genrsa -des3 -out ca.key 4096
$ openssl req -novo -x509 -days 365 -key ca.key -out ca.crt
para gerar seu próprio certificado CA e, em seguida, gere e assine as chaves do servidor e do cliente por meio de:
$ openssl genrsa -des3 -out server.key 4096
$ openssl req -novo -key server.key -out server.csr
$ openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 100 -out server.crt
e
$ openssl genrsa -des3 -out client.key 4096
$ openssl req -new -key client.key -out client.csr
$ openssl x509 -req -days 365 -em client.csr -CA ca.crt -CAkey ca.key -set_serial 101 -out client.crt
De resto, siga as etapas no link. O gerenciamento dos certificados para o Chrome funciona da mesma maneira que no exemplo mencionado para o Firefox.
Em seguida, configure o servidor via:
https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-apache-for-ubuntu-14-04
Observe que você já criou o servidor .crt e .key para não precisar mais executar essa etapa.
fonte
server.key
nãoclient.key
Conectei-me ao banco com SSL bidirecional (certificado de cliente e servidor) com o Spring Boot. Portanto, descreva aqui todas as minhas etapas, espero que ajude alguém (a solução de trabalho mais simples, eu encontrei):
Gere solicitação de certificado:
Gere chave privada:
Gere solicitação de certificado:
Manter
user.key
(e senha) e enviar solicitação de certificadouser.csr
ao banco para meu certificadoReceber 2 certificados: meu certificado raiz do cliente
clientId.crt
e certificado raiz do banco:bank.crt
Crie o keystore Java (digite a senha da chave e configure a senha do keystore):
Não preste atenção na saída:
unable to write 'random state'
. Java PKCS12keystore.p12
criado.Adicionar ao keystore
bank.crt
(para simplificar, usei um keystore):Verifique os certificados de keystore:
Pronto para o código Java :) Eu usei o Spring Boot
RestTemplate
comorg.apache.httpcomponents.httpcore
dependência adicional :fonte
Dado um arquivo p12 com o certificado e a chave privada (gerada pelo openssl, por exemplo), o código a seguir o utilizará para uma HttpsURLConnection específica:
A
SSLContext
leva algum tempo para inicializar, então você pode querer cache-lo.fonte
Acho que a correção aqui foi do tipo keystore, pkcs12 (pfx) sempre tem chave privada e o tipo JKS pode existir sem chave privada. A menos que você especifique em seu código ou selecione um certificado através do navegador, o servidor não tem como saber se está representando um cliente do outro lado.
fonte