Question

Est-il possible de créer proprement un certificat X509 en code Java sans utiliser les classes Bouncy Castle X509V * CertificateGenerator ?

Était-ce utile?

La solution

La possibilité de signer des certificats ne fait pas partie d'une bibliothèque ou d'une extension Java standard.

Une grande partie du code nécessaire pour le faire vous-même fait partie du noyau. Il existe des classes pour coder et décoder les noms X.500, les extensions de certificat X.509, les clés publiques de divers algorithmes et bien sûr, pour effectuer la signature numérique.

L’implémentation de ce logiciel par vous-même n’est pas anodine, mais c’est tout à fait faisable. J’ai probablement passé 4 ou 5 jours complets la première fois que j’ai fabriqué un prototype fonctionnel pour la signature de certificats. Ce fut un exercice d'apprentissage fantastique pour moi, mais il est difficile de justifier cette dépense lorsqu'il existe des bibliothèques utilisables disponibles gratuitement.

Autres conseils

Oui, mais pas avec les classes documentées publiquement. J'ai documenté le processus dans cet article .

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;
}   
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!");
    }
}

J'ai aimé la réponse de vbence, mais j'ai continué à avoir l'exception suivante:

java.security.cert.CertificateException: type de classe de sujet non valide.

Après de nombreuses tentatives pour savoir que était une classe de sujet valide, j'ai découvert que X509CerInfo souhaitait une instance de 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()));

Donc, les lignes 2 & amp; 3 nécessaires pour passer à

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

Tous les composants de base permettant de créer un certificat auto-signé (signature, encodage X509, etc.) sont disponibles dans JRE. Contrairement à la Colombie-Britannique, le JCE de Sun ne fournit aucun appel public pour signer un certificat. Cependant, toutes les fonctions sont disponibles dans Keytool. Vous pouvez simplement copier le code de keytool pour le faire. La méthode à copier est doSelfCert () .

Cela dépend de ce que vous voulez faire exactement (et probablement de votre définition de "Sanely"). Comme l'a souligné ZZ Coder, vous pouvez créer directement un certificat auto-signé en copiant outil clé . Mais je ne pense pas que vous puissiez créer un objet de demande de certificat PKCS10 avec le JCE standard, ce que vous devrez probablement faire si vous souhaitez créer des CEE standards signés par un CA.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top