2009-10-23 8 views

Antwort

13

Die Fähigkeit zum Signieren von Zertifikaten ist nicht Teil einer standardmäßigen Java-Bibliothek oder Erweiterung.

Eine Menge des Codes, der benötigt wird, um es selbst zu tun, ist Teil des Kerns. Es gibt Klassen zum Codieren und Decodieren von X.500-Namen, X.509-Zertifikatserweiterungen, öffentlichen Schlüsseln für verschiedene Algorithmen und natürlich zum Ausführen der digitalen Signatur.

Das Implementieren dieses selbst ist nicht trivial, aber es ist definitiv machbar — Ich verbrachte wahrscheinlich 4 oder 5 volle Tage das erste Mal, dass ich einen funktionierenden Prototyp für Zertifikatsignierung machte. Es war eine fantastische Lernübung für mich, aber es ist schwer, diese Kosten zu rechtfertigen, wenn es nutzbare Bibliotheken gibt, die kostenlos zur Verfügung stehen.

+0

Ist das noch genau wie 2017? – user674669

4

Alle grundlegenden Komponenten zum Erstellen eines selbstsignierten Zertifikats (Signieren, X509-Codierung usw.) sind in JRE verfügbar. Im Gegensatz zu BC bietet Sun JCE keine öffentlichen Aufrufe zum Signieren eines Zertifikats. Alle Funktionen sind jedoch in Keytool verfügbar. Sie können den Code einfach von keytool kopieren, um dies zu tun. Die Methode, die Sie kopieren müssen, lautet doSelfCert().

+4

Leider verwendet Keytool 'sun. *' Klassen dafür. Dies funktioniert nicht mit jeder JRE. Aber hier ist der [Quellcode] (https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/sun/security/tools/KeyTool.java) – Pith

1

Hängt davon ab, was genau Sie tun möchten (und wahrscheinlich Ihre Definition von "Sanely"). Wie ZZ Coder hervorhob, können Sie ein selbstsigniertes Zertifikat direkt erstellen, indem Sie keytool kopieren. Aber ich glaube nicht, dass Sie ein PKCS10-Zertifikatanforderungsobjekt mit der Standard-JCE erstellen können, was Sie wahrscheinlich tun müssen, wenn Sie Standard-CA-signierte EECs erstellen möchten.

+0

Hm, warum nicht ? Keytool kann eine selbstsignierte in eine CSR konvertieren, Sie müssen nur diesen Code kopieren. – eckes

63

Ja, aber nicht mit öffentlich dokumentierten Klassen. Ich habe den Prozess in this article dokumentiert.

import sun.security.x509.*; 
import java.security.cert.*; 
import java.security.*; 
import java.math.BigInteger; 
import java.util.Date; 
import java.io.IOException 

/**  
 * Create a self-signed X.509 Certificate 
 * @param dn the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB" 
 * @param pair the KeyPair 
 * @param days how many days from now the Certificate is valid for 
 * @param algorithm the signing algorithm, eg "SHA1withRSA" 
 */  
X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm) 
  throws GeneralSecurityException, IOException 
{ 
  PrivateKey privkey = pair.getPrivate(); 
  X509CertInfo info = new X509CertInfo(); 
  Date from = new Date(); 
  Date to = new Date(from.getTime() + days * 86400000l); 
  CertificateValidity interval = new CertificateValidity(from, to); 
  BigInteger sn = new BigInteger(64, new SecureRandom()); 
  X500Name owner = new X500Name(dn); 
  
  info.set(X509CertInfo.VALIDITY, interval); 
  info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn)); 
  info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner)); 
  info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner)); 
  info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic())); 
  info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); 
  AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid); 
  info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo)); 
  
  // Sign the cert to identify the algorithm that's used. 
  X509CertImpl cert = new X509CertImpl(info); 
  cert.sign(privkey, algorithm); 
  
  // Update the algorith, and resign. 
  algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG); 
  info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo); 
  cert = new X509CertImpl(info); 
  cert.sign(privkey, algorithm); 
  return cert; 
}    
+7

Ein sehr guter Tipp. Rettete mich davor, die gefürchtete (und geliebte) Bouncycastle lib zu importieren. Aufgeblasen! –

+11

Gibt es eine Möglichkeit, dies zu tun, die NICHT bedeutet, sun.security.x509. * Aufzurufen? In Anbetracht dessen, dass es in Wirklichkeit nicht etwas ist, das Sie verwenden sollten. –

+0

Ausgezeichnet. Ersparte mir eine Menge Arbeit. Der Code ist nett und sauber. Ich bearbeite den Code, um sicherzustellen, dass er nicht verschwindet, wenn der Blog ausfällt. – Suma

2
import sun.security.x509.*; 

import java.security.cert.*; 
import java.security.*; 
import java.math.BigInteger; 
import java.security.cert.Certificate; 
import java.util.Date; 
import java.io.IOException; 

public class Example { 
    /** 
    * Create a self-signed X.509 Example 
    * 
    * @param dn  the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB" 
    * @param pair  the KeyPair 
    * @param days  how many days from now the Example is valid for 
    * @param algorithm the signing algorithm, eg "SHA1withRSA" 
    */ 
    public X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm) 
      throws GeneralSecurityException, IOException { 
     PrivateKey privkey = pair.getPrivate(); 
     X509CertInfo info = new X509CertInfo(); 
     Date from = new Date(); 
     Date to = new Date(from.getTime() + days * 86400000l); 
     CertificateValidity interval = new CertificateValidity(from, to); 
     BigInteger sn = new BigInteger(64, new SecureRandom()); 
     X500Name owner = new X500Name(dn); 

     info.set(X509CertInfo.VALIDITY, interval); 
     info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn)); 
     info.set(X509CertInfo.SUBJECT, owner); 
     info.set(X509CertInfo.ISSUER, owner); 
     info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic())); 
     info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); 
     AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid); 
     info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo)); 

     // Sign the cert to identify the algorithm that's used. 
     X509CertImpl cert = new X509CertImpl(info); 
     cert.sign(privkey, algorithm); 

     // Update the algorith, and resign. 
     algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG); 
     info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo); 
     cert = new X509CertImpl(info); 
     cert.sign(privkey, algorithm); 
     return cert; 
    } 

    public static void main (String[] argv) throws Exception { 
     KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 
     KeyPair keyPair = keyPairGenerator.generateKeyPair(); 
     Example example = new Example(); 
     String distinguishedName = "CN=Test, L=London, C=GB"; 
     Certificate certificate = example.generateCertificateOriginal(distinguishedName, keyPair, 365, "SHA256withRSA"); 
     System.out.println("it worked!"); 
    } 
} 

Ich mochte Antwort des vbence, aber ich hielt die folgende Ausnahme erhalten:

java.security.cert.CertificateException: Betreff Klassentyp ungültig.

Nach vielen Versuchen, herauszufinden, war eine gültige Fachklasse Ich fand heraus, dass X509CerInfo wollte eine Instanz von X500Name.

1 info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn)); 
2 info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner)); 
3 info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner)); 
4 info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic())); 

So Linien 2 & 3 Änderungen erforderlich, um

2 info.set(X509CertInfo.SUBJECT, owner); 
3 info.set(X509CertInfo.ISSUER, owner);