¿Cómo importar un certificado X.509 existente y una clave privada en el almacén de claves Java para usar en SSL?

228

Tengo esto en una configuración de ActiveMQ:

<sslContext>
        <sslContext keyStore="file:/home/alex/work/amq/broker.ks"  
 keyStorePassword="password" trustStore="file:${activemq.base}/conf/broker.ts" 
 trustStorePassword="password"/>
</sslContext>

Tengo un par de certificados X.509 y un archivo de clave.

¿Cómo importo esos dos para usarlos en conectores SSL y SSL + stomp? Todos los ejemplos que pude google siempre generan la clave ellos mismos, pero ya tengo una clave.

Yo he tratado

keytool -import  -keystore ./broker.ks -file mycert.crt

pero esto solo importa el certificado y no el archivo de clave y da como resultado

2009-05-25 13:16:24,270 [localhost:61612] ERROR TransportConnector - Could not accept connection : No available certificate or key corresponds to the SSL cipher suites which are enabled.

Intenté concatenar el certificado y la clave, pero obtuve el mismo resultado.

¿Cómo importo la clave?

Aleksandar Ivanisevic
fuente
1
En realidad, debe escribir un poco de código para hacerlo, y los detalles dependen del formato de la clave privada que está intentando importar. ¿Qué formato es tu clave? ¿Puede explicar qué herramientas utilizó para generar la clave y el certificado que tiene?
erickson
Para SSL bidireccional (certificado de cliente y servidor) con Spring Boot, consulte stackoverflow.com/a/59317888/548473
Grigory Kislin el

Respuestas:

73

Lo creas o no, keytool no proporciona una funcionalidad tan básica como importar una clave privada al almacén de claves. Puede probar esta solución alternativa fusionando el archivo PKSC12 con la clave privada en un almacén de claves.

O simplemente use KeyMan más fácil de usar de IBM para el manejo del almacén de claves en lugar de keytool.exe.

Matej
fuente
11
Según la herramienta de respuesta de CoverosGene, Keytool lo admite desde Java 6. Este es el enlace que proporcionó
Houtman,
Para lo que vale, por todo el ruido sobre este tema, el mejor enlace es el enlace 'solución' de @Matej
cloudsurfin
2
Seguí la respuesta proporcionada por CoverosGene y funcionó.
Robert3452
1
KeyMan no me parece tan fácil de usar.
Malhechor el
15
Enlace roto. Incluya los detalles de la solución directamente en la respuesta :-(
lilalinux
536

Utilicé los siguientes dos pasos que encontré en los comentarios / publicaciones vinculados en las otras respuestas:

Paso uno: Convierta el certificado x.509 y la clave en un archivo pkcs12

openssl pkcs12 -export -in server.crt -inkey server.key \
               -out server.p12 -name [some-alias] \
               -CAfile ca.crt -caname root

Nota: asegúrese de poner una contraseña en el archivo pkcs12; de lo contrario, obtendrá una excepción de puntero nulo cuando intente importarla. (En caso de que alguien más tuviera este dolor de cabeza). (¡ Gracias jocull! )

Nota 2: es posible que desee agregar la -chainopción para preservar la cadena de certificados completa. ( Gracias Mafuba )

Paso dos: Convierta el archivo pkcs12 en un almacén de claves Java

keytool -importkeystore \
        -deststorepass [changeit] -destkeypass [changeit] -destkeystore server.keystore \
        -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass some-password \
        -alias [some-alias]

Terminado

OPCIONAL Paso cero: Crear certificado autofirmado

openssl genrsa -out server.key 2048
openssl req -new -out server.csr -key server.key
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

¡Salud!

reto
fuente
12
Asegúrese de poner una contraseña en el archivo p12; de lo contrario, obtendrá una excepción de referencia nula cuando intente importarla. (En caso de que alguien más ha tenido este dolor de cabeza)
jocull
99
En mi caso, en el paso uno, la opción -CAfile ca.crt -caname rootno generó correctamente los certificados de CA. En cambio, solía-certfile concatenedCAFiles.pem
dcernahoschi
11
No olvide utilizar el -chainargumento con openssl para incluir la cadena de certificados completa en su archivo pfx / p12 si lo desea en su almacén de claves.
Mafuba
3
En un entorno Windows, pvk2pfx(una herramienta VS estándar disponible en el cmdindicador VS ) .pfxescupirá un --equivalente a a .p12. El consejo de @ jocull sigue siendo relevante; ponle una contraseña. No es opensslnecesario
Ben Mosher
99
Para Tomcat en particular, es imprescindible que el almacén de claves y las contraseñas de las claves sean las mismas. Cuando importe una .p12clave, la contraseña del .p12.Tomcat original fallará java.security.UnrecoverableKeyException: Cannot recover key. En otras palabras: si necesita ejecutar -deststorepass changeit -srcstorepass some-passwordcon diferentes contraseñas, debe incluir -destkeypass changeit(con la misma contraseña que -deststorepass)
Slav
127

Keytool en Java 6 tiene esta capacidad: Importar claves privadas en un almacén de claves Java usando keytool

Aquí están los detalles básicos de esa publicación.

  1. Convierta el certificado existente a un PKCS12 usando OpenSSL. Se requiere una contraseña cuando se le solicita o el segundo paso se quejará.

    openssl pkcs12 -export -in [my_certificate.crt] -inkey [my_key.key] -out [keystore.p12] -name [new_alias] -CAfile [my_ca_bundle.crt] -caname root
  2. Convierta el PKCS12 a un archivo Java Keystore.

    keytool -importkeystore -deststorepass [new_keystore_pass] -destkeypass [new_key_pass] -destkeystore [keystore.jks] -srckeystore [keystore.p12] -srcstoretype PKCS12 -srcstorepass [pass_used_in_p12_keystore] -alias [alias_used_in_p12_keystore]
CoverosGene
fuente
44
La respuesta de @reto contiene el contenido de este enlace.
Mafuba
44
Según lo indicado por @Mafuba, aún debe crear un almacén de claves pkcs12 separado con una herramienta que no sea Java como openssl; entonces esto puede importarse a una tienda jks mediante keytool como se indica en la respuesta de reto.
Mister_Tom
Una cosa que hace que esta sea una buena respuesta es el hecho de que los certificados de entrada se especifican claramente entre paréntesis.
Mr.Budris
Fwiw, la salida del paso 1 ya debería ser utilizable como un almacén de claves de Java (por lo que el paso 2 puede no ser necesario - a menos que hagas necesidad de importar la clave cert + en una ya existente del almacén de claves) - como ya se ha mencionado en una respuesta anterior por @ jaco0646
Janaka Bandara
9

Y uno mas:

#!/bin/bash

# We have:
#
# 1) $KEY : Secret key in PEM format ("-----BEGIN RSA PRIVATE KEY-----") 
# 2) $LEAFCERT : Certificate for secret key obtained from some
#    certification outfit, also in PEM format ("-----BEGIN CERTIFICATE-----")   
# 3) $CHAINCERT : Intermediate certificate linking $LEAFCERT to a trusted
#    Self-Signed Root CA Certificate 
#
# We want to create a fresh Java "keystore" $TARGET_KEYSTORE with the
# password $TARGET_STOREPW, to be used by Tomcat for HTTPS Connector.
#
# The keystore must contain: $KEY, $LEAFCERT, $CHAINCERT
# The Self-Signed Root CA Certificate is obtained by Tomcat from the
# JDK's truststore in /etc/pki/java/cacerts

# The non-APR HTTPS connector (APR uses OpenSSL-like configuration, much
# easier than this) in server.xml looks like this 
# (See: https://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html):
#
#  <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
#                SSLEnabled="true"
#                maxThreads="150" scheme="https" secure="true"
#                clientAuth="false" sslProtocol="TLS"
#                keystoreFile="/etc/tomcat6/etl-web.keystore.jks"
#                keystorePass="changeit" />
#

# Let's roll:    

TARGET_KEYSTORE=/etc/tomcat6/foo-server.keystore.jks
TARGET_STOREPW=changeit

TLS=/etc/pki/tls

KEY=$TLS/private/httpd/foo-server.example.com.key
LEAFCERT=$TLS/certs/httpd/foo-server.example.com.pem
CHAINCERT=$TLS/certs/httpd/chain.cert.pem

# ----
# Create PKCS#12 file to import using keytool later
# ----

# From https://www.sslshopper.com/ssl-converter.html:
# The PKCS#12 or PFX format is a binary format for storing the server certificate,
# any intermediate certificates, and the private key in one encryptable file. PFX
# files usually have extensions such as .pfx and .p12. PFX files are typically used 
# on Windows machines to import and export certificates and private keys.

TMPPW=$$ # Some random password

PKCS12FILE=`mktemp`

if [[ $? != 0 ]]; then
  echo "Creation of temporary PKCS12 file failed -- exiting" >&2; exit 1
fi

TRANSITFILE=`mktemp`

if [[ $? != 0 ]]; then
  echo "Creation of temporary transit file failed -- exiting" >&2; exit 1
fi

cat "$KEY" "$LEAFCERT" > "$TRANSITFILE"

openssl pkcs12 -export -passout "pass:$TMPPW" -in "$TRANSITFILE" -name etl-web > "$PKCS12FILE"

/bin/rm "$TRANSITFILE"

# Print out result for fun! Bug in doc (I think): "-pass " arg does not work, need "-passin"

openssl pkcs12 -passin "pass:$TMPPW" -passout "pass:$TMPPW" -in "$PKCS12FILE" -info

# ----
# Import contents of PKCS12FILE into a Java keystore. WTF, Sun, what were you thinking?
# ----

if [[ -f "$TARGET_KEYSTORE" ]]; then
  /bin/rm "$TARGET_KEYSTORE"
fi

keytool -importkeystore \
   -deststorepass  "$TARGET_STOREPW" \
   -destkeypass    "$TARGET_STOREPW" \
   -destkeystore   "$TARGET_KEYSTORE" \
   -srckeystore    "$PKCS12FILE" \
   -srcstoretype  PKCS12 \
   -srcstorepass  "$TMPPW" \
   -alias foo-the-server

/bin/rm "$PKCS12FILE"

# ----
# Import the chain certificate. This works empirically, it is not at all clear from the doc whether this is correct
# ----

echo "Importing chain"

TT=-trustcacerts

keytool -import $TT -storepass "$TARGET_STOREPW" -file "$CHAINCERT" -keystore "$TARGET_KEYSTORE" -alias chain

# ----
# Print contents
# ----

echo "Listing result"

keytool -list -storepass "$TARGET_STOREPW" -keystore "$TARGET_KEYSTORE"
David Tonhofer
fuente
9

Primero convierta a p12:

openssl pkcs12 -export -in [filename-certificate] -inkey [filename-key] -name [host] -out [filename-new-PKCS-12.p12]

Crear nuevo JKS desde p12:

keytool -importkeystore -deststorepass [password] -destkeystore [filename-new-keystore.jks] -srckeystore [filename-new-PKCS-12.p12] -srcstoretype PKCS12
Michał Jurczuk
fuente
7

Sí, es un hecho triste que keytool no tiene funcionalidad para importar una clave privada.

Para el registro, al final fui con la solución descrita aquí

Aleksandar Ivanisevic
fuente
6

En mi caso, tenía un archivo pem que contenía dos certificados y una clave privada encriptada para usar en la autenticación SSL mutua. Entonces mi archivo pem se veía así:

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,C8BF220FC76AA5F9
...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

Aquí esta lo que hice:

Divida el archivo en tres archivos separados, de modo que cada uno contenga solo una entrada, comenzando con "--- BEGIN .." y terminando con las líneas "--- END ..". Supongamos que ahora tenemos tres archivos: cert1.pem cert2.pem y pkey.pem

Convierta pkey.pem al formato DER usando openssl y la siguiente sintaxis:

openssl pkcs8 -topk8 -nocrypt -in pkey.pem -inform PEM -out pkey.der -outform DER

Tenga en cuenta que si la clave privada está encriptada, debe proporcionar una contraseña (obtenerla del proveedor del archivo pem original) para convertirla al formato DER, openssl le pedirá la contraseña de esta manera: "ingrese una frase de contraseña para pkey .pem: "Si la conversión es exitosa, obtendrá un nuevo archivo llamado" pkey.der "

Cree un nuevo almacén de claves Java e importe la clave privada y los certificados:

String keypass = "password";  // this is a new password, you need to come up with to protect your java key store file
String defaultalias = "importkey";
KeyStore ks = KeyStore.getInstance("JKS", "SUN");

// this section does not make much sense to me, 
// but I will leave it intact as this is how it was in the original example I found on internet:   
ks.load( null, keypass.toCharArray());
ks.store( new FileOutputStream ( "mykeystore"  ), keypass.toCharArray());
ks.load( new FileInputStream ( "mykeystore" ),    keypass.toCharArray());
// end of section..


// read the key file from disk and create a PrivateKey

FileInputStream fis = new FileInputStream("pkey.der");
DataInputStream dis = new DataInputStream(fis);
byte[] bytes = new byte[dis.available()];
dis.readFully(bytes);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

byte[] key = new byte[bais.available()];
KeyFactory kf = KeyFactory.getInstance("RSA");
bais.read(key, 0, bais.available());
bais.close();

PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
PrivateKey ff = kf.generatePrivate (keysp);


// read the certificates from the files and load them into the key store:

Collection  col_crt1 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert1.pem"));
Collection  col_crt2 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert2.pem"));

Certificate crt1 = (Certificate) col_crt1.iterator().next();
Certificate crt2 = (Certificate) col_crt2.iterator().next();
Certificate[] chain = new Certificate[] { crt1, crt2 };

String alias1 = ((X509Certificate) crt1).getSubjectX500Principal().getName();
String alias2 = ((X509Certificate) crt2).getSubjectX500Principal().getName();

ks.setCertificateEntry(alias1, crt1);
ks.setCertificateEntry(alias2, crt2);

// store the private key
ks.setKeyEntry(defaultalias, ff, keypass.toCharArray(), chain );

// save the key store to a file         
ks.store(new FileOutputStream ( "mykeystore" ),keypass.toCharArray());

(opcional) Verifique el contenido de su nuevo almacén de claves:

keytool -list -keystore mykeystore -storepass password

Tipo de almacén de claves: JKS Proveedor de almacén de claves: SUN

Su almacén de claves contiene 3 entradas

cn = ..., ou = ..., o = .., 2 de septiembre de 2014, TrustedCertEntry, huella digital del certificado (SHA1): 2C: B8: ...

importkey, 2 de septiembre de 2014, PrivateKeyEntry, Certificado de huella digital (SHA1): 9C: B0: ...

cn = ..., o = ...., 2 de septiembre de 2014, TrustedCertEntry, huella digital de certificado (SHA1): 83:63: ...

(opcional) Pruebe sus certificados y clave privada de su nuevo almacén de claves en su servidor SSL: (Es posible que desee habilitar la depuración como una opción de VM: -Djavax.net.debug = all)

        char[] passw = "password".toCharArray();
        KeyStore ks = KeyStore.getInstance("JKS", "SUN");
        ks.load(new FileInputStream ( "mykeystore" ), passw );

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, passw);

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);
        TrustManager[] tm = tmf.getTrustManagers();

        SSLContext sclx = SSLContext.getInstance("TLS");
        sclx.init( kmf.getKeyManagers(), tm, null);

        SSLSocketFactory factory = sclx.getSocketFactory();
        SSLSocket socket = (SSLSocket) factory.createSocket( "192.168.1.111", 443 );
        socket.startHandshake();

        //if no exceptions are thrown in the startHandshake method, then everything is fine..

Finalmente, registre sus certificados con HttpsURLConnection si planea usarlo:

        char[] passw = "password".toCharArray();
        KeyStore ks = KeyStore.getInstance("JKS", "SUN");
        ks.load(new FileInputStream ( "mykeystore" ), passw );

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, passw);

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);
        TrustManager[] tm = tmf.getTrustManagers();

        SSLContext sclx = SSLContext.getInstance("TLS");
        sclx.init( kmf.getKeyManagers(), tm, null);

        HostnameVerifier hv = new HostnameVerifier()
        {
            public boolean verify(String urlHostName, SSLSession session)
            {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost()))
                {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };

        HttpsURLConnection.setDefaultSSLSocketFactory( sclx.getSocketFactory() );
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
Interkot
fuente
Sin embargo, Bruno mencionó que este verificador de nombre de host es incorrecto: "Su verificador de nombre de host es incorrecto, session.getPeerHost () no devuelve el nombre en el certificado, sino el nombre con el que se conectó (es decir, el urlHostName aquí), así que eso siempre va para ser verdad. Siempre estás volviendo verdad de todos modos. - Bruno ". Sin embargo, funcionó para mí, pero agradecería si alguien me muestra cómo escribir un buen verificador de nombre de host.
Interkot
1
Por supuesto, "funcionará" para usted, ya que nunca producirá un error, incluso cuando debería. Deje el verificador de nombre de host predeterminado utilizado en HttpsURLConnectionlugar de intentar escribir el suyo propio. (Otro problema con su ejemplo es que está utilizando el mismo almacén de claves que un almacén de claves y un almacén de confianza, lo cual no siempre es una buena idea ...)
Bruno
6

Usando los certificados Let's Encrypt

Suponiendo que haya creado sus certificados y claves privadas con Let's Encrypt en /etc/letsencrypt/live/you.com:

1. Cree un archivo PKCS # 12

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out pkcs.p12 \
        -name letsencrypt

Esto combina su certificado SSL fullchain.pemy su clave privada privkey.pemen un solo archivo, pkcs.p12.

Se le pedirá una contraseña para pkcs.p12 .

La exportopción especifica que se creará un archivo PKCS # 12 en lugar de analizarse (del manual ).

2. Crear el almacén de claves Java

keytool -importkeystore -destkeystore keystore.jks -srckeystore pkcs.p12 \
        -srcstoretype PKCS12 -alias letsencrypt

Si keystore.jksno existe, se creará con el pkcs.12archivo creado anteriormente. De lo contrario, importará pkcs.12al almacén de claves existente.


Estas instrucciones se derivan de esta publicación de blog .

Aquí hay más sobre los diferentes tipos de archivos en /etc/letsencrypt/live/you.com/.

Matthias Braun
fuente
5

En base a las respuestas anteriores, aquí se explica cómo crear un nuevo almacén de claves para su servidor web basado en Java, a partir de un certificado Comodo creado de forma independiente y una clave privada utilizando keytool (requiere JDK 1.6+)

  1. Emita este comando y en el indicador de contraseña ingrese somepass: 'server.crt' es el certificado de su servidor y 'server.key' es la clave privada que utilizó para emitir la CSR: openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12 -name www.yourdomain.com -CAfile AddTrustExternalCARoot.crt -caname "AddTrust External CA Root"

  2. Luego use keytool para convertir el almacén de claves p12 en un almacén de claves jks: keytool -importkeystore -deststorepass somepass -destkeypass somepass -destkeystore keystore.jks -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass somepass

Luego importe los otros dos certificados raíz / intermedios que recibió de Comodo:

  1. Importar COMODORSAAddTrustCA.crt: keytool -import -trustcacerts -alias cert1 -file COMODORSAAddTrustCA.crt -keystore keystore.jks

  2. Importar COMODORSADomainValidationSecureServerCA.crt: keytool -import -trustcacerts -alias cert2 -file COMODORSADomainValidationSecureServerCA.crt -keystore keystore.jks

Fotios Basagiannis
fuente
4

Puede seguir estos pasos para importar la clave a un almacén de claves existente. Las instrucciones se combinan de las respuestas en este hilo y otros sitios. Estas instrucciones funcionaron para mí (el almacén de claves de Java):

  1. correr

openssl pkcs12 -export -in yourserver.crt -inkey yourkey.key -out server.p12 -name somename -certfile yourca.crt -caname root

(Si es necesario, coloque la opción -chain. Poner eso falló para mí). Esto le pedirá la contraseña: debe proporcionar la contraseña correcta; de lo contrario, recibirá un error (error de encabezado o error de relleno, etc.).

  1. Le pedirá que ingrese una nueva contraseña; debe ingresar una contraseña aquí; ingrese todo menos recordarlo. (Supongamos que entras en Aragorn).
  2. Esto creará el archivo server.p12 en formato pkcs.
  3. Ahora, para importarlo en el *.jksarchivo, ejecute:
    keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore yourexistingjavakeystore.jks -deststoretype JKS -deststorepass existingjavastorepassword -destkeypass existingjavastorepassword
    (Muy importante, no omita los parámetros deststorepass y destkeypass).
  4. Le pedirá la contraseña del almacén de claves src. Entra en Aragorn y pulsa enter. El certificado y la clave ahora se importan a su almacén de claves java existente.
vanval
fuente
3

Las respuestas anteriores señalan correctamente que solo puede hacer esto con las herramientas JDK estándar al convertir primero el archivo JKS al formato PKCS # 12. Si está interesado, preparé una utilidad compacta para importar claves derivadas de OpenSSL en un almacén de claves con formato JKS sin tener que convertir primero el almacén de claves a PKCS # 12: http://commandlinefanatic.com/cgi-bin/showarticle. cgi? article = art049

Usaría la utilidad vinculada de esta manera:

$ openssl req -x509 -newkey rsa:2048 -keyout localhost.key -out localhost.csr -subj "/CN=localhost"

(firme el CSR, regrese localhost.cer)

$ openssl rsa -in localhost.key -out localhost.rsa
Enter pass phrase for localhost.key:
writing RSA key
$ java -classpath . KeyImport -keyFile localhost.rsa -alias localhost -certificateFile localhost.cer -keystore localhost.jks -keystorePassword changeit -keystoreType JKS -keyPassword changeit
Joshua Davies
fuente
Simplemente vincular a su propia biblioteca (o utilidad) no es una buena respuesta. Al vincularlo, explicar por qué resuelve el problema, proporcionar un código que lo use para hacerlo y rechazarlo es una mejor respuesta. Ver: ¿Cómo puedo vincularme a un recurso externo de manera amigable para la comunidad?
Mogsdad el
No estoy seguro de lo que quieres decir con "renuncia", pero agregué un ejemplo.
Joshua Davies
¡Excelente! Ese es un comentario enlatado, por lo que parte no se aplica: la renuncia significa informar sobre su afiliación con el producto o servicio vinculado, lo que hizo con "
Junté
3

Si tiene un archivo PEM (por ejemplo server.pem) que contiene:

  • el certificado de confianza
  • la clave privada

entonces puede importar el certificado y la clave en un almacén de claves JKS como este:

1 ) Copie la clave privada del archivo PEM en un archivo ASCII (por ejemplo server.key)

2 ) Copie el certificado del archivo PEM en un archivo ascii (por ejemplo server.crt)

3 ) Exporte el certificado y la clave a un archivo PKCS12:

$ openssl pkcs12 -export -in server.crt -inkey server.key \
                 -out server.p12 -name [some-alias] -CAfile server.pem -caname root
  • el archivo PEM se puede usar como argumento para la -CAfileopción .
  • se le solicita una contraseña de 'exportación'.
  • si hace esto en git bash, agregue winptyal inicio del comando para que se pueda ingresar la contraseña de exportación.

4 ) Convierta el archivo PKCS12 en un almacén de claves JKS:

$ keytool -importkeystore -deststorepass changeit -destkeypass changeit \
          -destkeystore keystore.jks  -srckeystore server.p12 -srcstoretype PKCS12 \
          -srcstorepass changeit
  • la srcstorepasscontraseña debe coincidir con la contraseña de exportación del paso 3)
Joman68
fuente
3

Lo que estaba tratando de lograr era usar la clave privada y el certificado ya proporcionados para firmar el mensaje que iba a algún lugar que necesitaba asegurarme de que el mensaje provenía de mí (las claves privadas firman mientras se cifran las claves públicas).

Entonces, si ya tiene un archivo .key y un archivo .crt?

Prueba esto:

Paso 1: Convierta la clave y el certificado a un archivo .p12

openssl pkcs12 -export -in certificate.crt -inkey privateKey.key -name alias -out yourconvertedfile.p12

Paso 2: importe la clave y cree un archivo .jsk con un solo comando

keytool -importkeystore -deststorepass changeit -destkeystore keystore.jks -srckeystore umeme.p12 -srcstoretype PKCS12

Paso 3: en tu java:

char[] keyPassword = "changeit".toCharArray();

KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyStoreData = new FileInputStream("keystore.jks");

keyStore.load(keyStoreData, keyPassword);
KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(keyPassword);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("alias", entryPassword);

System.out.println(privateKeyEntry.toString());

Si necesita firmar alguna cadena con esta clave, haga lo siguiente:

Paso 1: convierta el texto que desea cifrar

byte[] data = "test".getBytes("UTF8");

Paso 2: Obtenga la clave privada codificada en base64

keyStore.load(keyStoreData, keyPassword);

//get cert, pubkey and private key from the store by alias
Certificate cert = keyStore.getCertificate("localhost");
PublicKey publicKey = cert.getPublicKey();
KeyPair keyPair = new KeyPair(publicKey, (PrivateKey) key);

//sign with this alg
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initSign(keyPair.getPrivate());
sig.update(data);
byte[] signatureBytes = sig.sign();
System.out.println("Signature:" + Base64.getEncoder().encodeToString(signatureBytes));

sig.initVerify(keyPair.getPublic());
sig.update(data);

System.out.println(sig.verify(signatureBytes));

Referencias

  1. ¿Cómo importar un certificado x509 existente y una clave privada en el almacén de claves Java para usar en SSL?
  2. http://tutorials.jenkov.com/java-cryptography/keystore.html
  3. http://www.java2s.com/Code/Java/Security/RetrievingaKeyPairfromaKeyStore.htm
  4. Cómo firmar una cadena con clave privada

Programa final

public static void main(String[] args) throws Exception {

    byte[] data = "test".getBytes("UTF8");

    // load keystore
    char[] keyPassword = "changeit".toCharArray();

    KeyStore keyStore = KeyStore.getInstance("JKS");
    //System.getProperty("user.dir") + "" < for a file in particular path 
    InputStream keyStoreData = new FileInputStream("keystore.jks");
    keyStore.load(keyStoreData, keyPassword);

    Key key = keyStore.getKey("localhost", keyPassword);

    Certificate cert = keyStore.getCertificate("localhost");

    PublicKey publicKey = cert.getPublicKey();

    KeyPair keyPair = new KeyPair(publicKey, (PrivateKey) key);

    Signature sig = Signature.getInstance("SHA1WithRSA");

    sig.initSign(keyPair.getPrivate());
    sig.update(data);
    byte[] signatureBytes = sig.sign();
    System.out.println("Signature:" + Base64.getEncoder().encodeToString(signatureBytes));

    sig.initVerify(keyPair.getPublic());
    sig.update(data);

    System.out.println(sig.verify(signatureBytes));
}
Mwa Joe
fuente
1

Simplemente haga un almacén de claves PKCS12, Java puede usarlo directamente ahora. De hecho, si enumera un almacén de claves de estilo Java, la herramienta clave en sí misma le alerta sobre el hecho de que PKCS12 es ahora el formato preferido.

openssl pkcs12 -export -in server.crt -inkey server.key \
               -out server.p12 -name [some-alias] \
               -CAfile ca.crt -caname root -chain

Debería haber recibido los tres archivos (server.crt, server.key, ca.crt) de su proveedor de certificados. No estoy seguro de lo que realmente significa "raíz de nombre", pero parece que debe especificarse de esa manera.

En el código Java, asegúrese de especificar el tipo de almacén de claves correcto.

KeyStore.getInstance("PKCS12")

Obtuve mi certificado SSL emitido comodo.com que funciona bien en NanoHTTPD de esta manera.

Stefan Reich
fuente