【问题标题】:Decode/Read a CSR (Certificate Signing Request) Using Java or BouncyCastle使用 Java 或 BouncyCastle 解码/读取 CSR(证书签名请求)
【发布时间】:2014-02-20 15:35:06
【问题描述】:

我正在使用代码生成 CSR(证书签名请求),但相关信息没有问题。我需要指针来弄清楚如何使用 Java 和/或 BouncyCastle 读取 CSR 内容。

感谢任何指针或想法。

【问题讨论】:

标签: java security ssl bouncycastle


【解决方案1】:

想通了:

  1. 将 CSR PEM 转换为 PKCS10CertificationRequest
  2. 通过访问 PKCS10CertificationRequest 实例的 getSubject() 方法获取 X500Name 实例
  3. 遍历 RDN[] 数组并使用 ASN1ObjectIdentifier 之一获取您想要的特定字段(例如 COUNTRY 是 2.5.4.6)

代码如下:

public class EncryptDecrypt {
    private Logger LOG = LoggerFactory.getLogger(EncryptDecrypt.class);
    private final String COUNTRY = "2.5.4.6";
    private final String STATE = "2.5.4.8";
    private final String LOCALE = "2.5.4.7";
    private final String ORGANIZATION = "2.5.4.10";
    private final String ORGANIZATION_UNIT = "2.5.4.11";
    private final String COMMON_NAME = "2.5.4.3";


    @Test
    public void testReadCertificateSigningRequest() {
        String csrPEM = "-----BEGIN CERTIFICATE REQUEST-----\n" +
                "MIICwjCCAaoCAQAwfTELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0Zsb3JpZGExEzAR\n" +
                "BgNVBAcTCkJvY2EgUmF0b24xGzAZBgNVBAoTEkxvb25leSBUb29ucywgSW5jLjEU\n" +
                "MBIGA1UECxMLRGV2ZWxvcG1lbnQxFDASBgNVBAMTC2V4YW1wbGUuY29tMIIBIjAN\n" +
                "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiJCj31d1Rp+aKz/GTkedaiS/VSCc\n" +
                "PRARYgXukobjgBHx46HjldAcfg/DoANn5lEQaFxaIZJLbZ/AdLUyw/hUbU0CjWXv\n" +
                "pN3Ep3o9XgRTPkIFoI22VOI/O2ZLjBq/E4DWyVmv+vG6BK0LRh7hykzPCw6KIRR9\n" +
                "NCmUMJMQX5d5P/r1lR5H399pnLcLsrHoWDwBSEDgkGWyxnvEB0+/bIz42T3qnlFt\n" +
                "7avarxlHG2p5DoRTf8GJ+6imY88ZeBW/Nk18aDINsAHWLv383JICIAsZ3VuMk8m/\n" +
                "Z/Z5b21zIuZECDJjZjvAAjr/shVLB+Pck5+HJy6tqj79MJOQu+jKIrK8VwIDAQAB\n" +
                "oAAwDQYJKoZIhvcNAQEFBQADggEBAGtuAAHG4OC9jSRjGWSqfMXTDMz9tgekDREA\n" +
                "SYv5QIrOXsMzwbgDw8LxRJZEskl4JJOnjwEvUXWUF1M6XmG2h358nOnrkOlsumHw\n" +
                "Tx5gGSr6S6aJO/HG46erctE8aWpnFZYMfuEkul4ApsIufL7Bxqs3NHZWcrWBlLIP\n" +
                "aVCKx1FPRMC36Tj3EslbuUB/iTRt90Nfq1IxHMIKiwCiSNJSqfRVLANhI8MUbOjB\n" +
                "CBly1wcH68WWNkyvHVvbcF/B9AfYG9AqWjZjygKpyf81VZWctXhDc8UtomqrblXN\n" +
                "mvz4RKpIhZQLuuxlBrdzJkPm2sOdtdZghebCRRVWdjsig4sylgQ=\n" +
                "-----END CERTIFICATE REQUEST-----";

        PKCS10CertificationRequest csr = convertPemToPKCS10CertificationRequest(csrPEM);

        X500Name x500Name = csr.getSubject();
        System.out.println("x500Name is: " + x500Name + "\n");

        // country is 2.5.4.6
        System.out.println("COUNTRY: " + getX500Field(COUNTRY, x500Name));
        // state is 2.5.4.8
        System.out.println("STATE: " + getX500Field(STATE, x500Name));
        // locale is 2.5.4.7
        System.out.println("LOCALE: " + getX500Field(LOCALE, x500Name));


    }

    private String getX500Field(String asn1ObjectIdentifier, X500Name x500Name) {
        RDN[] rdnArray = x500Name.getRDNs(new ASN1ObjectIdentifier(asn1ObjectIdentifier));
        String retVal = null;
        for (RDN item : rdnArray) {
            retVal = item.getFirst().getValue().toString();
        }

        return retVal;
    }

    private PKCS10CertificationRequest convertPemToPKCS10CertificationRequest(String pem) {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        PKCS10CertificationRequest csr = null;
        ByteArrayInputStream pemStream = null;
        try {
            pemStream = new ByteArrayInputStream(pem.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException ex) {
            LOG.error("UnsupportedEncodingException, convertPemToPublicKey", ex);
        }

        Reader pemReader = new BufferedReader(new InputStreamReader(pemStream));
        PEMParser pemParser = new PEMParser(pemReader);

        try {
            Object parsedObj = pemParser.readObject();

            System.out.println("PemParser returned: " + parsedObj);

            if (parsedObj instanceof PKCS10CertificationRequest) {
                csr = (PKCS10CertificationRequest) parsedObj;

            }
        } catch (IOException ex) {
            LOG.error("IOException, convertPemToPublicKey", ex);
        }

        return csr;
    }

    private String toPEM(Object key) {
        StringWriter sw = new StringWriter();
        PEMWriter pem = new PEMWriter(sw);
        try {
            pem.writeObject(key);
            pem.close();
        } catch (IOException e) {
            System.out.printf("IOException: %s%n", e);
        }
        return sw.toString();
    }
}

【讨论】:

  • 值得注意的是ASN1ObjectIdentifiers 以public static final ASN1ObjectIdentifiers 的形式存储在BCStyle 静态类中,因此COUNTRY 之类的东西不需要从零重新创建。但是,它不是enum。
  • 很好,谢谢分享。请参阅下面的 Kotlin/Android 更新代码。
【解决方案2】:

我提出这个“简单”的解决方案来阅读 csr

你必须用

添加依赖
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcmail-jdk15on</artifactId>
    <version>1.62</version>
</dependency>

创建新对象 CSRObject

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;

import java.io.*;

public class CSRObject {
    private final X500Name x500Name;

    public CSRObject(final String csr) throws IOException {
        final Reader pemReader = new StringReader(csr);
        final PEMParser pemParser = new PEMParser(pemReader);
        x500Name = ((PKCS10CertificationRequest) pemParser.readObject()).getSubject();
    }


    public String get(final CSRObjectEnum field) {
        RDN[] rdnArray = x500Name.getRDNs(new ASN1ObjectIdentifier(field.code));
        String retVal = null;
        for (RDN item : rdnArray) {
            retVal = item.getFirst().getValue().toString();
        }
        return retVal;
    }

    public enum CSRObjectEnum {
        COUNTRY("2.5.4.6"),
        STATE("2.5.4.8"),
        LOCALE("2.5.4.7"),
        ORGANIZATION("2.5.4.10"),
        ORGANIZATION_UNIT("2.5.4.11"),
        COMMON_NAME("2.5.4.3"),//
        ;
        private final String code;

        CSRObjectEnum(final String sCode) {
            code = sCode;
        }

    }
}

你可以用这个方法测试:

@Test
public void test() throws IOException {
    final CSRObject csr = new CSRObject(TEST_CERTIF);
    for (final CSRObject.CSRObjectEnum field : CSRObject.CSRObjectEnum.values()){
        LOGGER.info("{}:{}", field.name(), csr.get(field));
    }
}

TEST_CERTIF 是字符串

private static final String TEST_CERTIF = "-----BEGIN CERTIFICATE REQUEST-----\n" +
        "...\n" +
        "-----END CERTIFICATE REQUEST-----\n";

【讨论】:

    【解决方案3】:

    我在 David's 答案的基础上验证了 CSR 内容,以便在 Android 上的 Kotlin 中进行单元测试。它假定您以字符串格式开头的 CSR。 CSR 是使用 SpongyCastle JcaPKCS10CertificationRequestBuilder 生成的。

    class yourCsrTestClass {
        ...
        private lateinit var csrContent: PKCS10CertificationRequest
        ...
        @Test
        fun yourCsrTest() {
            //This creates a CSR with SpongyCastle which we will test
            val csr = yourCSRService.generateRequest()
    
            //Convert our CSR string in modified code from David
            convertCsrString(csr)
    
            //Get x500Name subject
            val x500Name = csrContent.subject
    
            //Assert test as true if content matches as intended
            //This can be applied to any CSR attribute
            assertTrue(getX500Field(BCStrictStyle.O.toString(), x500Name) == "Your intender organization name")
        }
        ...
        private fun convertCsrString(pemCsr: String) {
            val stream = ByteArrayInputStream(pemCsr.toByteArray())
    
            val pemReader = BufferedReader(InputStreamReader(stream))
            var pemParser: PEMParser? = null
            try {
                pemParser = PEMParser(pemReader)
                val parsedObj = pemParser.readObject()
                println("PemParser returned: $parsedObj")
                if (parsedObj is PKCS10CertificationRequest) {
                    csrContent = parsedObj
                }
            } catch (ex: IOException) {
                Log.d("IOException, convertPemToPublicKey", ex.toString())
            } finally {
                if (pemParser != null) {
                    IOUtils.closeQuietly(pemParser)
                }
            }
        }
        ...
        private fun getX500Field(asn1ObjectIdentifier: String, x500Name: X500Name): String {
            val rdnArray = x500Name.getRDNs(ASN1ObjectIdentifier(asn1ObjectIdentifier))
    
            return rdnArray[0].first.value.toString()
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-11-28
      • 2014-08-23
      • 2016-02-23
      • 2011-02-19
      • 1970-01-01
      • 2015-09-23
      • 2017-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多