2009-05-29 22 views
11

Estoy buscando una biblioteca o código java para generar certificados, claves públicas y privadas sobre la marcha sin utilizar programas de terceros (como openssl).Generar certificados, claves públicas y privadas con Java

Creo que algo está haciendo keytool + openssl pero desde código Java.

Considere una aplicación web basada en Java servlet asegurada con ssl y autentificación de cliente. Quiero que el contenedor de servlets genere certificados de cliente (p. Ej., Formato pkcs12) bajo pedido solo con código Java.

Gracias, Peter.

+0

alternativa sólo podría invocar la clase java herramienta de claves sol y proporcionar los parámetros necesarios para generar los certificados. Pero estas clases están en el paquete com.sun * y potencialmente cambiarán. En teoría, todo está presente en Java para generar sus propios certificados, pero no está disponible públicamente. –

Respuesta

9

Puede generar Certificado en Java dinámicamente, utilizando un par o claves. (Clave pública, Claves privadas). Obtenga estas claves como formato BigInteger y verifique el siguiente código para generar el certificado.

RSAPrivateKeySpec serPrivateSpec = new RSAPrivateKeySpec(
    new BigInteger(val of pub key), new BigInteger(val of pri key)); 
fact = KeyFactory.getInstance("RSA"); 
PrivateKey serverPrivateKey = fact.generatePrivate(serPrivateSpec); 

RSAPublicKeySpec serPublicSpec = new RSAPublicKeySpec(
    new BigInteger(agentCL.getSerPubMod()), new BigInteger(agentCL.getSerPubExp())); 
PublicKey serverPublicKey = fact.generatePublic(serPublicSpec); 

keyStore = KeyStore.getInstance(IMXAgentCL.STORE_TYPE); 
keyStore.load(null, SOMEPWD.toCharArray()); 

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 

X509Certificate[] serverChain = new X509Certificate[1]; 
X509V3CertificateGenerator serverCertGen = new X509V3CertificateGenerator(); 
X500Principal serverSubjectName = new X500Principal("CN=OrganizationName"); 
serverCertGen.setSerialNumber(new BigInteger("123456789")); 
// X509Certificate caCert=null; 
serverCertGen.setIssuerDN(somename); 
serverCertGen.setNotBefore(new Date()); 
serverCertGen.setNotAfter(new Date()); 
serverCertGen.setSubjectDN(somename); 
serverCertGen.setPublicKey(serverPublicKey); 
serverCertGen.setSignatureAlgorithm("MD5WithRSA"); 
// certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,new 
// AuthorityKeyIdentifierStructure(caCert)); 
serverCertGen.addExtension(X509Extensions.SubjectKeyIdentifier, false, 
    new SubjectKeyIdentifierStructure(serverPublicKey)); 
serverChain[0] = serverCertGen.generateX509Certificate(serverPrivateKey, "BC"); // note: private key of CA 

keyStore.setEntry("xyz", 
    new KeyStore.PrivateKeyEntry(serverPrivateKey, serverChain), 
    new KeyStore.PasswordProtection("".toCharArray())); 

Hope esto le ayudará.

+1

Solo agregando el proveedor Bouncy Castle JSSE, que no has mencionado en tu respuesta. – EJP

3

Legado Advertencia Begin:

  • Este código sólo establece el CommonName/CN/Asunto.
  • El lugar correcto ahora es el SubjectAltName.

De Chrome Deprecates Subject CN Matching:

Chrome 58, será necesario que los certificados de especificar el nombre de host (s) al que se aplican en el campo SubjectAltName; valores en el campo Asunto serán ignorados."

Legado Final Warning

import java.io.FileOutputStream; 
import java.security.KeyStore; 
import java.security.PrivateKey; 
import java.security.cert.X509Certificate; 
import java.util.Date; 

import sun.security.x509.CertAndKeyGen; 
import sun.security.x509.X500Name; 

public class UseKeyTool { 

    private static final int keysize = 1024; 
    private static final String commonName = "www.test.de"; 
    private static final String organizationalUnit = "IT"; 
    private static final String organization = "test"; 
    private static final String city = "test"; 
    private static final String state = "test"; 
    private static final String country = "DE"; 
    private static final long validity = 1096; // 3 years 
    private static final String alias = "tomcat"; 
    private static final char[] keyPass = "changeit".toCharArray(); 

    // copied most ideas from sun.security.tools.KeyTool.java 

    @SuppressWarnings("restriction") 
    public static void main(String[] args) throws Exception { 

     KeyStore keyStore = KeyStore.getInstance("JKS"); 
     keyStore.load(null, null); 

     CertAndKeyGen keypair = new CertAndKeyGen("RSA", "SHA1WithRSA", null); 

     X500Name x500Name = new X500Name(commonName, organizationalUnit, organization, city, state, country); 

     keypair.generate(keysize); 
     PrivateKey privKey = keypair.getPrivateKey(); 

     X509Certificate[] chain = new X509Certificate[1]; 

     chain[0] = keypair.getSelfCertificate(x500Name, new Date(), (long) validity * 24 * 60 * 60); 

     keyStore.setKeyEntry(alias, privKey, keyPass, chain); 

     keyStore.store(new FileOutputStream(".keystore"), keyPass); 



    } 
} 
+1

Los nombres DNS * no * se supone que están en 'commonName' (suponiendo que se supone que debe agregarse en el código anterior). La práctica ha sido desaprobada tanto por IETF como por CA/Browser Forums. Los nombres DNS deben ir en 'subjectAltNames', pero el código carece de él. – jww

+1

DigiCert parece estar en desacuerdo: "Para proteger https://www.example.com, su nombre común debe ser www.example.com o * .example.com para un certificado de comodín". https://www.digicert.com/easy-csr/keytool.htm –

+0

Consulte [RFC 6125] (http://tools.ietf.org/html/rfc6125), Sección 6.4.4 o el CA/Browser [ Requisitos básicos de seguridad] (https://cabforum.org/wp-content/uploads/Baseline_Requirements_V1_1_9.pdf), Sección 9.2.2. DidgiCert debería saberlo mejor ya que son [miembros de la CA/B] (https://cabforum.org/members/). – jww

Cuestiones relacionadas