将x509证书写入java中的PEM格式化字符串?

时间:2010-07-22 20:14:46

标签: java x509 pem der

是否有一些高级方法将X509Certificate写入PEM格式的字符串? 目前我正在使用x509cert.encode()将其写入DER格式的字符串,然后对其进行64位编码并附加页眉和页脚来创建PEM字符串,但这看起来很糟糕。特别是因为我也必须在线下休息。

10 个答案:

答案 0 :(得分:55)

这还不错。 Java不提供任何编写PEM文件的功能。你正在做的是正确的方法。甚至KeyTool都做同样的事情,

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

如果您使用BouncyCastle,您可以使用PEMWriter类在PEM中写出X509证书。

答案 1 :(得分:17)

以前的答案给出了3de party软件(如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;
}

答案 2 :(得分:15)

还没有看到有人提出Java 8的Base64.getMimeEncoder方法 - 实际上允许你指定行长行分隔符,如下所示:

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

我看看这个^与标准编码器有什么不同,我找不到任何东西。对于BASIC和MIME编码器,javadoc引用了RFC 2045,并为BASIC添加了RFC 4648。 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;
}

答案 3 :(得分:10)

以下不使用大型外部库或可能版本不一致的sun。*库。它建立在judoman的答案之上,但它也按照OpenSSL,Java和其他人的要求,以64个字符分块。

导入:

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();
}

(我会对Judoman的回答发表评论,但我没有足够的声誉点可以发表评论,我的简单编辑被拒绝了,因为它应该是评论或答案,所以这就是答案。 )

如果您想直接写入文件,还需要import java.io.FileWriter和:

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

答案 4 :(得分:8)

基于ZZ Coder的想法,但不使用不保证在JRE版本之间保持一致的sun.misc类,请考虑这个

使用班级:

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();
}

答案 5 :(得分:8)

如果您有充气城堡的PEMWriter,那么您可以执行以下操作:

进口:

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();
}

答案 6 :(得分:3)

几乎与@ Andy Brown少一行代码。

StringWriter sw = new StringWriter();

try (JcaPEMWriter jpw = new JcaPEMWriter(sw)) {
    jpw.writeObject(cert);
}

String pem = sw.toString();

他说PEMWriter已过时。

答案 7 :(得分:1)

使用一些小的Base64,我做了下面的事情,它不依赖于base64或bouncycastle之类的其他东西。

import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
class Convert {
    private static byte[] convertToPem(X509Certificate cert)
        throws CertificateEncodingException {
        String cert_begin = "-----BEGIN CERTIFICATE-----\n";
        String end_cert = "-----END CERTIFICATE-----\n";
        String b64 = encode(cert.getEncoded()).replaceAll("(.{64})", "$1\n");
        if (b64.charAt(b64.length() - 1) != '\n') end_cert = "\n" + end_cert;
        String outpem = cert_begin + b64 + end_cert;
        return outpem.getBytes();
    }

    // Taken from https://gist.github.com/EmilHernvall/953733
    private static String encode(byte[] data) {
        String tbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        StringBuilder buffer = new StringBuilder();
        int pad = 0;
        for (int i = 0; i < data.length; i += 3) {
            int b = ((data[i] & 0xFF) << 16) & 0xFFFFFF;
            if (i + 1 < data.length) b |= (data[i+1] & 0xFF) << 8;
            else pad++;
            if (i + 2 < data.length) b |= (data[i+2] & 0xFF);
            else pad++;
            for (int j = 0; j < 4 - pad; j++, b <<= 6) {
                int c = (b & 0xFC0000) >> 18;
                buffer.append(tbl.charAt(c));
            }
        }
        for (int j = 0; j < pad; j++) buffer.append("=");
        return buffer.toString();
    }
}

答案 8 :(得分:0)

使用Guava's 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());

答案 9 :(得分:0)

在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已被缓冲,因此在访问构造它的编写器之前,确实需要刷新/关闭它。