web-dev-qa-db-fra.com

Écrire un certificat x509 dans une chaîne au format PEM en java?

Existe-t-il un moyen simple d’écrire un X509Certificate dans une chaîne au format PEM? créer une chaîne PEM, mais cela semble mauvais. Surtout que je dois aussi faire la queue. 

42
pizzathehut

Ce n'est pas mal. Java ne fournit aucune fonction pour écrire des fichiers PEM. Ce que vous faites est la bonne façon. Même KeyTool fait la même chose,

BASE64Encoder encoder = new BASE64Encoder();
out.println(X509Factory.BEGIN_CERT);
encoder.encodeBuffer(cert.getEncoded(), out);
out.println(X509Factory.END_CERT);

Si vous utilisez BouncyCastle, vous pouvez utiliser la classe PEMWriter pour écrire un certificat X509 dans PEM.

55
ZZ Coder

La réponse précédente donne des problèmes de compatibilité avec les logiciels tiers (comme PHP), car le certificat PEM n'est pas correctement tronqué.

Importations:

import org.Apache.commons.codec.binary.Base64;

Code:

protected static String convertToPem(X509Certificate cert) throws CertificateEncodingException {
 Base64 encoder = new Base64(64);
 String cert_begin = "-----BEGIN CERTIFICATE-----\n";
 String end_cert = "-----END CERTIFICATE-----";

 byte[] derCert = cert.getEncoded();
 String pemCertPre = new String(encoder.encode(derCert));
 String pemCert = cert_begin + pemCertPre + end_cert;
 return pemCert;
}
17
kthomeer

Personne n'a encore vu la méthode Base64.getMimeEncoder de Java 8 - vous permet en fait de spécifier le séparateur de longueur de ligne et de ligne comme suit:

final Base64.Encoder encoder = Base64.getMimeEncoder(64, LINE_SEPARATOR.getBytes());

J'ai regardé pour voir s'il y avait une différence avec ceci ^ par rapport à l'encodeur standard, et je n'ai rien trouvé. Le javadoc cites RFC 2045 pour les codeurs BASIC et MIME, avec l’ajout de RFC 4648 pour BASIC. Si je comprends bien, ces deux normes utilisent le même alphabet Base64 (les tableaux ont la même apparence), vous devriez donc pouvoir utiliser MIME si vous devez spécifier une longueur de ligne.

Cela signifie qu'avec Java 8, ceci peut être accompli avec:

import Java.security.cert.Certificate;
import Java.security.cert.CertificateEncodingException;
import Java.util.Base64;

...

public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
public static final String END_CERT = "-----END CERTIFICATE-----";
public final static String LINE_SEPARATOR = System.getProperty("line.separator");

...

public static String formatCrtFileContents(final Certificate certificate) throws CertificateEncodingException {
    final Base64.Encoder encoder = Base64.getMimeEncoder(64, LINE_SEPARATOR.getBytes());

    final byte[] rawCrtText = certificate.getEncoded();
    final String encodedCertText = new String(encoder.encode(rawCrtText));
    final String prettified_cert = BEGIN_CERT + LINE_SEPARATOR + encodedCertText + LINE_SEPARATOR + END_CERT;
    return prettified_cert;
}
13
JoshC13

Les éléments suivants n'utilisent pas de bibliothèques externes volumineuses ni éventuellement de bibliothèques Sun. * incohérentes. Il s'appuie sur la réponse de judoman, mais il coupe également les lignes de 64 caractères, comme requis par OpenSSL, Java et autres.

Importation:

import javax.xml.bind.DatatypeConverter;
import Java.security.cert.X509Certificate;
import Java.io.StringWriter;

Code:

public static String certToString(X509Certificate cert) {
    StringWriter sw = new StringWriter();
    try {
        sw.write("-----BEGIN CERTIFICATE-----\n");
        sw.write(DatatypeConverter.printBase64Binary(cert.getEncoded()).replaceAll("(.{64})", "$1\n"));
        sw.write("\n-----END CERTIFICATE-----\n");
    } catch (CertificateEncodingException e) {
        e.printStackTrace();
    }
    return sw.toString();
}

(J'aurais juste commenté la réponse de judoman, mais je n'ai pas assez de points de réputation pour pouvoir commenter, et ma modification simple a été rejetée car elle aurait dû être un commentaire ou une réponse, alors voici la réponse.)

Si vous voulez écrire directement dans un fichier, import Java.io.FileWriter et:

FileWriter fw = new FileWriter(certFilePath);
fw.write(certToString(myCert));
fw.close();
10
jtbr

Pour tirer parti de l'idée de ZZ Coder, mais sans utiliser les classes Sun.misc dont la cohérence entre les versions de JRE n'est pas garantie, considérez ceci.

Classe d'utilisation:

import javax.xml.bind.DatatypeConverter;

Code:

try {
    System.out.println("-----BEGIN CERTIFICATE-----");
    System.out.println(DatatypeConverter.printBase64Binary(x509cert.getEncoded()));
    System.out.println("-----END CERTIFICATE-----");
} catch (CertificateEncodingException e) {
    e.printStackTrace();
}
8
judoman

Si vous avez PEMWriter du château gonflable, vous pouvez alors:

Importations:

import org.bouncycastle.openssl.PEMWriter;

Code:

/**
 * Converts a {@link X509Certificate} instance into a Base-64 encoded string (PEM format).
 *
 * @param x509Cert A X509 Certificate instance
 * @return PEM formatted String
 * @throws CertificateEncodingException
 */
public String convertToBase64PEMString(Certificate x509Cert) throws IOException {
    StringWriter sw = new StringWriter();
    try (PEMWriter pw = new PEMWriter(sw)) {
        pw.writeObject(x509Cert);
    }
    return sw.toString();
}

Dans BouncyCastle, 1.60 PEMWriter a été déconseillé en faveur de PemWriter.

StringWriter sw = new StringWriter();

try (PemWriter pw = new PemWriter(sw)) {
  PemObjectGenerator gen = new JcaMiscPEMGenerator(cert);
  pw.writeObject(gen);
}

return sw.toString();

PemWriter est en mémoire tampon, vous devez donc la vider/la fermer avant d'accéder au scripteur avec lequel il a été construit.

0
Andy Brown

Encore une autre alternative pour l'encodage avec BaseEncoding de Guava :

import com.google.common.io.BaseEncoding;

public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final int LINE_LENGTH = 64;

Et alors:

String encodedCertText = BaseEncoding.base64()
                                     .withSeparator(LINE_SEPARATOR, LINE_LENGTH)
                                     .encode(cert.getEncoded());
0
Ahmad Abdelghany