【问题标题】:unable to extract public key from x509 cert无法从 x509 证书中提取公钥
【发布时间】:2015-12-31 16:19:59
【问题描述】:

这是我的代码:

import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;

class LoadKey {
    public static void main(String[] args)
    throws InvalidKeySpecException, UnsupportedEncodingException, NoSuchAlgorithmException
    {
        String cert = "-----BEGIN CERTIFICATE-----\n" +
                      "MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM\n" +
                      "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg\n" +
                      "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x\n" +
                      "MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\n" +
                      "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw\n" +
                      "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n" +
                      "gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy\n" +
                      "wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B\n" +
                      "d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM\n" +
                      "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl\n" +
                      "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF\n" +
                      "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw\n" +
                      "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0\n" +
                      "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF\n" +
                      "AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp\n" +
                      "ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le\n" +
                      "IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==\n" +
                      "-----END CERTIFICATE-----\n";
        System.out.println(cert);
        byte[] encodedCert = cert.getBytes();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedCert);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
    }
}

OpenSSL 能够通过命令行解码 X509 证书,所以我知道它是一个有效的证书。但是Java似乎并不喜欢它,都一样。

我已经厌倦了有和没有尾随的 \n 都无济于事。

有什么想法吗?

【问题讨论】:

  • 您有一个 PEM 文本证书,您在计算机的默认字符集中获得该字符串的字节,您将这些与加密内容无关的字节传递给 key i> 相关的工厂,你预计会发生什么?
  • 也许它期待一个\r\n?您是否尝试过先从文件中读取它?
  • @OlegEstekhin - 好吧cert.getBytes("UTF-8") 也无济于事。正如我在帖子中所说,OpenSSL (openssl x509 -in mycert.pem -noout -text) 可以很好地读取这些字节,你怎么能说这些字节与加密的东西无关?如果这些字节与加密的东西没有任何关系,而不是什么字节序列?如果 Java 只是决定抛弃所有 IETF RFC 并制定自己的标准,那它就是一种天哪,该死的无用语言。
  • @neubert 不是人,也不是。你只是错过了一些东西。 PEM 编码为 Base64,您需要先解码字符串。请参阅此处的示例stackoverflow.com/questions/11787571/…

标签: java rsa x509


【解决方案1】:

---更新

正如 cmets 中 dave_thompson_085 所提到的,OP 的解决方案唯一有问题的是 OP 使用 KeyFactory 用于密钥,而不是 CertificateFactory 用于证书。

这是代码没有 Base64 转换,因为 CertificateFactory 可以自己读取 PEM 文件(它会查找 BEGIN/END CERTIFICATE 阻止自己知道它正在读取 PEM 文件)。

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;


class LoadKey {
    public static void main(String[] args)
    throws Exception
    {
        String cert = "-----BEGIN CERTIFICATE-----\n" +
                      "MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM\n" +
                      "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg\n" +
                      "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x\n" +
                      "MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\n" +
                      "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw\n" +
                      "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n" +
                      "gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy\n" +
                      "wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B\n" +
                      "d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM\n" +
                      "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl\n" +
                      "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF\n" +
                      "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw\n" +
                      "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0\n" +
                      "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF\n" +
                      "AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp\n" +
                      "ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le\n" +
                      "IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==\n" +
                      "-----END CERTIFICATE-----\n";

        System.out.println(cert);

        byte[] certBytes = cert.getBytes(java.nio.charset.StandardCharsets.UTF_8);

        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(certBytes);
        X509Certificate certificate = (X509Certificate)certFactory.generateCertificate(in);

        System.out.println("Subject DN : " + certificate.getSubjectDN().getName());
        System.out.println("Issuer : " + certificate.getIssuerDN().getName());
        System.out.println("Not After: " + certificate.getNotAfter());
        System.out.println("Not Before: " + certificate.getNotBefore());
        System.out.println("version: " + certificate.getVersion());
        System.out.println("serial number : " + certificate.getSerialNumber());

        PublicKey publicKey = certificate.getPublicKey();
        System.out.println("PublicKey : \n" + publicKey);
    }
}

你缺少 base64 解码部分。见上面的评论

这是工作代码,您需要 Apache Commons Codec Base64 类库。

注意:查看上面的代码,上面的base64步骤是CertificateFactory自动完成的,不需要手动完成。

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

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

class LoadKey {
    public static void main(String[] args)
    throws Exception
    {
        String cert = "-----BEGIN CERTIFICATE-----\n" +
                      "MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM\n" +
                      "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg\n" +
                      "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x\n" +
                      "MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\n" +
                      "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw\n" +
                      "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n" +
                      "gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy\n" +
                      "wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B\n" +
                      "d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM\n" +
                      "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl\n" +
                      "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF\n" +
                      "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw\n" +
                      "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0\n" +
                      "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF\n" +
                      "AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp\n" +
                      "ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le\n" +
                      "IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==\n" +
                      "-----END CERTIFICATE-----\n";

        cert = cert.replace("-----BEGIN CERTIFICATE-----\n", "");
        cert = cert.replace("-----END CERTIFICATE-----\n", "");
        System.out.println(cert);

        byte[] encodedCert = cert.getBytes("UTF-8");
        byte[] decodedCert = Base64.decodeBase64(encodedCert);
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(decodedCert);
        X509Certificate certificate = (X509Certificate)certFactory.generateCertificate(in);

        System.out.println("Subject DN : " + certificate.getSubjectDN().getName());
        System.out.println("Issuer : " + certificate.getIssuerDN().getName());
        System.out.println("Not After: " + certificate.getNotAfter());
        System.out.println("Not Before: " + certificate.getNotBefore());
        System.out.println("version: " + certificate.getVersion());
        System.out.println("serial number : " + certificate.getSerialNumber());

        PublicKey publicKey = certificate.getPublicKey();
        System.out.println("PublicKey : \n" + publicKey);
    }
}

输出

MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM
MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x
MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy
wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B
d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM
BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp
ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le
IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==

Subject DN : CN=www.google.com, O=Google Inc, L=Mountain View, ST=California, C=US
Issuer : CN=Thawte SGC CA, O=Thawte Consulting (Pty) Ltd., C=ZA
Not After: Mon Sep 30 19:59:59 EDT 2013
Not Before: Tue Oct 25 20:00:00 EDT 2011
version: 3
serial number : 105827261859531100510423749949966875981
PublicKey : 
Sun RSA public key, 1024 bits
  modulus: 156396091895984667473837837332877995558144703880815901117439532534031286131520903863087599986938779606924811933611903716377206837300122262900786662124968110191717844999183338594373129421417536020806373385428322642107305024162536996222164292639147591878860587271770855626780464602884552232097424473091745159379
  public exponent: 65537

【讨论】:

  • 使用 Java 8,您还可以使用 java.util.Base64().getDecoder().decode() 来避免 Apache 公共依赖
  • 实际上,OP 的唯一问题是使用 KeyFactory 而不是 CertificateFactory 作为证书。 CertificateFactory 可以读取 PEM 或 DER,因此您根本不需要解码,因此不需要公共 j8:只需通过 (PEM ) 数据流。
猜你喜欢
  • 1970-01-01
  • 2017-06-13
  • 2017-05-03
  • 2014-06-23
  • 1970-01-01
  • 2012-07-17
  • 2018-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多