2009-05-29 6 views
11

Я ищу библиотеку java или код для генерации сертификатов, открытых и закрытых ключей на лету без использования сторонних программ (таких как openssl).Создание сертификатов, открытых и закрытых ключей с Java

Я думаю что-то, что делает keytool + openssl, но из кода Java.

Рассмотрите веб-приложение на основе сервлета, защищенное ssl и аутентификацией клиента. Я хочу, чтобы контейнер сервлетов генерировал клиентские сертификаты (например, формат pkcs12) по запросу только с кодом Java.

спасибо, Питер.

+0

В качестве альтернативы вы можете просто вызвать класс Java Keytool SUN и обеспечивают необходимые параметры для создания сертификатов. Но эти классы находятся в пакете com.sun * и потенциально могут измениться. В теории все присутствует в Java для создания собственных сертификатов, но оно не является общедоступным. –

ответ

9

Вы можете генерировать сертификат в Java динамически, используя пару или ключи. (Открытый ключ, приватные ключи). Получите эти ключи как формат BigInteger и проверите следующий код для создания сертификата.

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())); 

Надеюсь, это вам поможет.

+1

Только добавив провайдера Bouncy Castle JSSE, который вы не упомянули в вашем ответе. – EJP

3

Наследство Предупреждение Начало:

  • Этот код только устанавливает CommonName/CN/Тема.
  • Правильное место сейчас SubjectAltName.

От Chrome Deprecates Subject CN Matching:

Chrome 58 будет требовать, чтобы сертификаты указать имя хоста (ов), к которому они применяются в области SubjectAltName; Значения в поле Тема будет игнорироваться.»

Наследство Предупреждение Конец

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

DNS-имена * не * предполагается, что они находятся в 'commonName' (предполагая, что это должно быть добавлено в код выше). Практика устарела и на форумах IETF, и на CA/Browser. Имена DNS должны находиться в 'subjectAltNames', но в коде отсутствует. – jww

+1

DigiCert, похоже, не согласен: «Чтобы защитить https://www.example.com, ваше общее имя должно быть www.example.com или * .example.com для подстановочного сертификата». https://www.digicert.com/easy-csr/keytool.htm –

+0

Проверьте [RFC 6125] (http://tools.ietf.org/html/rfc6125), раздел 6.4.4 или CA/Browser [ Базовые требования к безопасности] (https://cabforum.org/wp-content/uploads/Baseline_Requirements_V1_1_9.pdf), раздел 9.2.2. DidgiCert должен знать лучше, поскольку они являются [членами CA/B] (https://cabforum.org/members/). – jww