Есть ли способ высокого уровня записи X509Certificate в форматированную строку PEM? В настоящее время я делаю x509cert.encode(), чтобы записать его в форматированную строку DER, затем базовую кодировку 64 и добавив верхний и нижний колонтитулы для создания строки PEM, но это кажется плохим. Тем более, что я тоже должен бросить перерывы.
Записать сертификат x509 в строку в формате PEM в java?
Ответ 1
Это не плохо Java не предоставляет никаких функций для записи файлов PEM. То, что вы делаете, это правильный путь. Даже KeyTool делает то же самое,
BASE64Encoder encoder = new BASE64Encoder();
out.println(X509Factory.BEGIN_CERT);
encoder.encodeBuffer(cert.getEncoded(), out);
out.println(X509Factory.END_CERT);
Если вы используете BouncyCastle, вы можете использовать класс PEMWriter для записи сертификата X509 в PEM.
Ответ 2
Предыдущий ответ дает проблемы совместимости с 3-сторонним программным обеспечением (таким как PHP), потому что сертификат PEM неправильно распределен.
Импорт:
import org.apache.commons.codec.binary.Base64;
Код:
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;
}
Ответ 3
Еще не видел, чтобы кто-нибудь Base64.getMimeEncoder
метод Java 8 Base64.getMimeEncoder
- фактически позволяет указать длину строки и разделитель строк следующим образом:
final Base64.Encoder encoder = Base64.getMimeEncoder(64, LINE_SEPARATOR.getBytes());
Я посмотрел, есть ли какая-нибудь разница с этим ^ по сравнению со стандартным кодером, и я не смог ничего найти. Javadoc ссылается на RFC 2045 для BASIC и MIME-кодеров, с добавлением RFC 4648 для BASIC. В AFAIK оба этих стандарта используют один и тот же алфавит Base64 (таблицы выглядят одинаково), поэтому вам следует использовать MIME, если вам нужно указать длину строки.
Это означает, что с Java 8 это может быть достигнуто с помощью:
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;
}
Ответ 4
В следующих случаях не используются большие внешние библиотеки или, возможно, несовместимые с версией sun. * библиотеки. Он основывается на ответе судей, но он также разбивает строки на 64 символа, как того требуют OpenSSL, Java и другие.
Импорт
import javax.xml.bind.DatatypeConverter;
import java.security.cert.X509Certificate;
import java.io.StringWriter;
код:
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();
}
(Я бы просто прокомментировал ответ на судейство, но у меня недостаточно очков репутации, которые можно прокомментировать, и мое простое редактирование было отклонено, потому что это должен был комментарий или ответ, так что вот ответ. )
Если вы хотите написать прямо в файл, также import java.io.FileWriter
и:
FileWriter fw = new FileWriter(certFilePath);
fw.write(certToString(myCert));
fw.close();
Ответ 5
Чтобы основываться на идее ZZ Coder, но без использования классов sun.misc
, которые не гарантируют согласованности между версиями JRE, рассмотрите этот
Использовать класс:
import javax.xml.bind.DatatypeConverter;
код:
try {
System.out.println("-----BEGIN CERTIFICATE-----");
System.out.println(DatatypeConverter.printBase64Binary(x509cert.getEncoded()));
System.out.println("-----END CERTIFICATE-----");
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
Ответ 6
Если у вас есть PEMWriter из bouncy castle, вы можете сделать следующее:
Импорт:
import org.bouncycastle.openssl.PEMWriter;
Код:
/**
* 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();
}
Ответ 7
Еще одна альтернатива для кодирования с использованием Guava BaseEncoding:
import com.google.common.io.BaseEncoding;
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final int LINE_LENGTH = 64;
А потом:
String encodedCertText = BaseEncoding.base64()
.withSeparator(LINE_SEPARATOR, LINE_LENGTH)
.encode(cert.getEncoded());
Ответ 8
В BouncyCastle 1.60 PEMWriter
устарела в пользу PemWriter
.
StringWriter sw = new StringWriter();
try (PemWriter pw = new PemWriter(sw)) {
PemObjectGenerator gen = new JcaMiscPEMGenerator(cert);
pw.writeObject(gen);
}
return sw.toString();
PemWriter
буферизуется, поэтому вам нужно очистить/закрыть его перед доступом к устройству записи, с которым он был создан.