Je dois créer un certificat X509 auto-signé avec Bouncy Castle en Java, mais chaque classe que j'essaie d'inclure est obsolète. Comment puis-je résoudre ça? Y a-t-il une autre classe à inclure? Merci
Mise à jour de la réponse de @Bewusstsein. Les classes de Bouncycastle sont obsolètes dans la dernière version à compter de cette réponse (11/05/2017). Si vous utilisez la dernière version (1.55) ou une version relativement récente:
public static Certificate selfSign(KeyPair keyPair, String subjectDN) throws OperatorCreationException, CertificateException, IOException
{
Provider bcProvider = new BouncyCastleProvider();
Security.addProvider(bcProvider);
long now = System.currentTimeMillis();
Date startDate = new Date(now);
X500Name dnName = new X500Name(subjectDN);
BigInteger certSerialNumber = new BigInteger(Long.toString(now)); // <-- Using the current timestamp as the certificate serial number
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.add(Calendar.YEAR, 1); // <-- 1 Yr validity
Date endDate = calendar.getTime();
String signatureAlgorithm = "SHA256WithRSA"; // <-- Use appropriate signature algorithm based on your keyPair algorithm.
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate());
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, keyPair.getPublic());
// Extensions --------------------------
// Basic Constraints
BasicConstraints basicConstraints = new BasicConstraints(true); // <-- true for CA, false for EndEntity
certBuilder.addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, basicConstraints); // Basic Constraints is usually marked as critical.
// -------------------------------------
return new JcaX509CertificateConverter().setProvider(bcProvider).getCertificate(certBuilder.build(contentSigner));
}
BEWARE: Cette réponse utilise une ancienne version de la bibliothèque avec 11 CVE .
Voici ce que j'utilise (avec BouncyCastle v1.38):
import Java.math.BigInteger;
import Java.security.InvalidKeyException;
import Java.security.KeyPair;
import Java.security.KeyPairGenerator;
import Java.security.NoSuchAlgorithmException;
import Java.security.NoSuchProviderException;
import Java.security.SecureRandom;
import Java.security.Security;
import Java.security.SignatureException;
import Java.util.Date;
import javax.security.auth.x500.X500Principal;
import Java.security.cert.CertificateEncodingException;
import Java.security.cert.X509Certificate;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V3CertificateGenerator;
public class BouncyCastle {
public static void main(String[] args) throws CertificateEncodingException, InvalidKeyException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException {
X509Certificate selfSignedX509Certificate = new BouncyCastle().generateSelfSignedX509Certificate();
System.out.println(selfSignedX509Certificate);
}
public X509Certificate generateSelfSignedX509Certificate() throws CertificateEncodingException, InvalidKeyException, IllegalStateException,
NoSuchProviderException, NoSuchAlgorithmException, SignatureException {
addBouncyCastleAsSecurityProvider();
// generate a key pair
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
keyPairGenerator.initialize(4096, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// build a certificate generator
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
X500Principal dnName = new X500Principal("cn=example");
// add some options
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setSubjectDN(new X509Name("dc=name"));
certGen.setIssuerDN(dnName); // use the same
// yesterday
certGen.setNotBefore(new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000));
// in 2 years
certGen.setNotAfter(new Date(System.currentTimeMillis() + 2 * 365 * 24 * 60 * 60 * 1000));
certGen.setPublicKey(keyPair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
certGen.addExtension(X509Extensions.ExtendedKeyUsage, true,
new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping));
// finally, sign the certificate with the private key of the same KeyPair
X509Certificate cert = certGen.generate(keyPair.getPrivate(), "BC");
return cert;
}
public void addBouncyCastleAsSecurityProvider() {
Security.addProvider(new BouncyCastleProvider());
}
}
Pour que certGen.generate(keyPair.getPrivate(), "BC");
fonctionne, BouncyCastle doit être ajouté en tant que fournisseur de sécurité.
J'ai confirmé que cela fonctionne avec cette dépendance maven:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.38</version>
</dependency>
Voici un générateur de certificats ECDSA auto-signé complet qui crée des certificats utilisables dans les connexions TLS, côté client et côté serveur. Il a été testé avec BouncyCastle 1.57. Un code similaire peut être utilisé pour créer des certificats RSA.
SecureRandom random = new SecureRandom();
// create keypair
KeyPairGenerator keypairGen = KeyPairGenerator.getInstance("EC");
keypairGen.initialize(256, random);
KeyPair keypair = keypairGen.generateKeyPair();
// fill in certificate fields
X500Name subject = new X500NameBuilder(BCStyle.INSTANCE)
.addRDN(BCStyle.CN, "stackoverflow.com")
.build();
byte[] id = new byte[20];
random.nextBytes(id);
BigInteger serial = new BigInteger(160, random);
X509v3CertificateBuilder certificate = new JcaX509v3CertificateBuilder(
subject,
serial,
Date.from(LocalDate.of(2000, 1, 1).atStartOfDay(ZoneOffset.UTC).toInstant()),
Date.from(LocalDate.of(2035, 1, 1).atStartOfDay(ZoneOffset.UTC).toInstant()),
subject,
keypair.getPublic());
certificate.addExtension(Extension.subjectKeyIdentifier, false, id);
certificate.addExtension(Extension.authorityKeyIdentifier, false, id);
BasicConstraints constraints = new BasicConstraints(true);
certificate.addExtension(
Extension.basicConstraints,
true,
constraints.getEncoded());
KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.digitalSignature);
certificate.addExtension(Extension.keyUsage, false, usage.getEncoded());
ExtendedKeyUsage usageEx = new ExtendedKeyUsage(new KeyPurposeId[] {
KeyPurposeId.id_kp_serverAuth,
KeyPurposeId.id_kp_clientAuth
});
certificate.addExtension(
Extension.extendedKeyUsage,
false,
usageEx.getEncoded());
// build BouncyCastle certificate
ContentSigner signer = new JcaContentSignerBuilder("SHA256withECDSA")
.build(keypair.getPrivate());
X509CertificateHolder holder = certificate.build(signer);
// convert to JRE certificate
JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
converter.setProvider(new BouncyCastleProvider());
X509Certificate x509 = converter.getCertificate(holder);
// serialize in DER format
byte[] serialized = x509.getEncoded();
C'est le code utilisé par BouncyCastle lui-même pour générer des certificats X.509. Vous aurez besoin de this et this bibliothèque de BC pour l'utiliser. Pour plus de détails sur la façon de l’utiliser, jetez peut-être un coup d’œil à this question (classe principale).
public class BCCertGen {
public static String _country = "Westeros",
_organisation = "Targaryen",
_location = "Valyria",
_state = "Essos",
_issuer = "Some Trusted CA";
public BCCertGen(String country, String organisation, String location, String state, String issuer){
_country = country;
_organisation = organisation;
_location = location;
_state = state;
_issuer = issuer;
}
public static X509Certificate generate(PrivateKey privKey, PublicKey pubKey, int duration, String signAlg, boolean isSelfSigned) throws Exception{
Provider BC = new BouncyCastleProvider();
// distinguished name table.
X500NameBuilder builder = createStdBuilder();
// create the certificate
ContentSigner sigGen = new JcaContentSignerBuilder(signAlg).build(privKey);
X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
new X500Name("cn="+_issuer), //Issuer
BigInteger.valueOf(1), //Serial
new Date(System.currentTimeMillis() - 50000), //Valid from
new Date((long)(System.currentTimeMillis() + duration*8.65*Math.pow(10,7))), //Valid to
builder.build(), //Subject
pubKey //Publickey to be associated with the certificate
);
X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
cert.checkValidity(new Date());
if (isSelfSigned) {
// check verifies in general
cert.verify(pubKey);
// check verifies with contained key
cert.verify(cert.getPublicKey());
}
ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
return (X509Certificate) fact.generateCertificate(bIn);
}
private static X500NameBuilder createStdBuilder() {
X500NameBuilder builder = new X500NameBuilder(RFC4519Style.INSTANCE);
builder.addRDN(RFC4519Style.c, _country);
builder.addRDN(RFC4519Style.o, _organisation);
builder.addRDN(RFC4519Style.l, _location);
builder.addRDN(RFC4519Style.st, _state);
return builder;
}
}
EDIT: Je ne me souviens plus de quel test BC je l’ai pris exactement, mais voici quelque chose de similaire https://github.com/bcgit/bc-Java/blob/master/prov/src/test/Java/org /bouncycastle/pqc/jcajce/provider/test/KeyStoreTest.Java