1. Overview
1.概述
The Common Name (CN) is an attribute within the Distinguished Name (DN) field in an X.509 certificate. The CN is usually the domain name of the organization to which the certificate belongs. Sometimes, we need to access the CN value from the certificate file in our application.
通用名称(CN)是 X.509 证书中区别名称(DN)字段中的一个属性。CN 通常是证书所属组织的域名。有时,我们需要在应用程序中访问证书文件中的 CN 值。
In this tutorial, we’ll learn different ways of extracting the CN value in Java.
在本教程中,我们将学习 在 Java 中提取 CN 值的不同方法。
2. Common Name
2.通用名称
A certificate contains information about the owner of the certificate: duration of validity, certificate usage, DN, etc.
证书包含证书所有者的信息:有效期、证书使用情况、DN 等。
The Distinguished Name or DN essentially consists of a set of name-value pairs, with names like Country (C), Organization (O), Organizational Unit (OU), CN, and a few others.
区分名称或 DN 主要由一组名称-值对组成,名称包括国家 (C)、组织 (O)、组织单位 (OU)、CN 和其他一些名称。
A DN looks something like “CN=Baeldung, L=Casablanca, ST=Morocco, C=MA“. As shown in this example, the CN is usually the domain name of the site.
DN 看起来像”CN=Baeldung, L=Casablanca, ST=Morocco, C=MA“。如图所示,CN 通常是网站的域名。
To extract the CN from an X.509 certificate in Java, we can do the following:
用 Java 从 X.509 证书中提取 CN 的方法如下:
- Parse the certificate
- Get its DN
- Parse the DN to extract the CN
In the following sections, we’ll extract the CN using different libraries.
在接下来的章节中,我们将使用不同的库提取 CN。
3. Using the BouncyCastle
3.使用弹跳城堡
BouncyCastle is a collection of APIs for the cryptographic operations that complements the default Java Cryptographic Extension (JCE). Also, it provides an easy way to get information about the certificate.
BouncyCastle是用于加密操作的 API 集合,是对默认 Java Cryptographic Extension (JCE) 的补充。此外,它还提供了一种获取证书信息的简便方法。
3.1. Maven Dependency
3.1.Maven 依赖
Let’s start by declaring the bouncycastle dependency in our pom.xml:
首先,让我们在 pom.xml 中声明 bouncycastle 依赖关系:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
3.2. Extract the CN
3.2.提取 CN
First, let’s get an X509Certificate object from our certificate file:
首先,让我们从证书文件中获取一个 X509Certificate 对象:
Security.addProvider(new BouncyCastleProvider());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "BC");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream("src/main/resources/Baeldung.cer"));
In the code above, we register the BouncyCastleProvider as a security provider using the addProvider() method. After that, we create a CertificateFactory object using the getInstance() method. The getInstance() method takes two arguments – the certificate type “X.509” and the security provider “BC“. The certificateFactory instance is subsequently used to generate an X509Certificate object via the generateCertificate() method.
在上面的代码中,我们使用 addProvider() 方法将 BouncyCastleProvider 注册为安全提供程序。然后,我们使用 getInstance() 方法创建一个 CertificateFactory 对象。getInstance() 方法需要两个参数–证书类型”X.509“和安全提供者”BC“。certificateFactory 实例随后将用于通过 generateCertificate() 方法生成 X509Certificate 对象。
Next, let’s get the CN from the X509Certificate object:
接下来,让我们从 X509Certificate 对象中获取 CN:
@Test
void whenUsingBouncyCastle_thenExtractCommonName() {
X500Principal principal = certificate.getSubjectX500Principal();
X500Name x500Name = new X500Name(principal.getName());
RDN[] rdns = x500Name.getRDNs(BCStyle.CN);
List<String> names = new ArrayList<>();
for (RDN rdn : rdns) {
String name = IETFUtils.valueToString(rdn.getFirst().getValue());
names.add(name);
}
for (String commonName : names) {
assertEquals("Baeldung", commonName);
}
}
In this code, we retrieve the subject DN in X500Principal format using the getSubjectX500Principal() method. Then, we convert that DN into BouncyCastle’s X500Name representation. After that, we extract the CNs from the X500Name object via the getRDNs() method.
在这段代码中,我们使用 getSubjectX500Principal() 方法获取 X500Principal 格式的主题 DN。然后,我们将 DN 转换为 BouncyCastle 的 X500Name 表示法。然后,我们通过 getRDNs() 方法从 X500Name 对象中提取 CN。
An RDN is a BouncyCastle class that represents a single part of the X.500Name object. An X.500Name object is composed of several RDNs, each of which consists of an attribute type and an attribute value. Finally, we use the BCStyle.CN, which is a BouncyCastle constant for the CN attribute type.
RDN 是一个 BouncyCastle 类,代表 X.500Name 对象的一个单独部分。一个 X.500Name 对象由多个 RDN 组成,每个 RDN 由一个属性类型和一个属性值组成。最后,我们使用 BCStyle.CN, 作为 CN 属性类型的 BouncyCastle 常量。
4. Using Regular Expressions
4.使用正则表达式
Regular expressions (regex) are a powerful tool for string manipulation in Java. We can use it to extract the CN from a certificate.
正则表达式 (regex) 是 Java 中一种强大的字符串操作工具。我们可以使用它从证书中提取 CN。
Let’s create a test case to extract the CN:
让我们创建一个测试用例来提取 CN:
@Test
void whenUsingRegex_thenExtractCommonName() {
X500Principal principal = certificate.getSubjectX500Principal();
List<String> names = new ArrayList<>();
Pattern pattern = Pattern.compile("CN=([^,]+)");
Matcher matcher = pattern.matcher(principal.getName());
while (matcher.find()) {
names.add(matcher.group(1));
}
for (String commonName : names) {
assertEquals("Baeldung", commonName);
}
}
In the above code, we use the Pattern and Matcher classes. We first create a Pattern object by calling its static compile() method and passing it the “CN=([^,]+)” pattern. Then, we create a Matcher object by calling the Pattern object’s matcher() method and passing it the DN value. Finally, we call the find() method in the Matcher object.
在上述代码中,我们使用了 Pattern 和 Matcher 类。首先,我们通过调用静态 compile() 方法创建一个 Pattern 对象,并将 “CN=([^,]+)” 模式传递给它。然后,我们调用 Pattern 对象的 matcher() 方法并传递 DN 值,从而创建 Matcher 对象。最后,我们调用 Matcher 对象中的 find() 方法。
5. Using the Cryptacular Library
5.使用 Cryptacular 库
Another way of getting the CN value from the certificate is by using the Cryptacular library.
从证书中获取 CN 值的另一种方法是使用 Cryptacular 库。
5.1. Maven Dependency
5.1.Maven 依赖关系
Let’s declare the cryptacular dependency in our pom.xml:
让我们在 pom.xml 中声明 cryptacular 依赖关系:
<dependency>
<groupId>org.cryptacular</groupId>
<artifactId>cryptacular</artifactId>
<version>1.2.6</version>
</dependency>
5.2. Extract the CN
5.2.提取 CN
Let’s create a test case in which we extract the CN using the CertUtil class:
让我们创建一个测试用例,使用 CertUtil 类提取 CN:
@Test
void whenUsingCryptacular_thenExtractCommonName() {
String commonName = CertUtil.subjectCN(certificate);
assertEquals("Baeldung", commonName);
}
We use the subjectCN() method to extract the CN from the X509Certificate object.
我们使用 subjectCN() 方法从 X509Certificate 对象中提取 CN。
Also, we should note that when a certificate has multiple CNs, this library only returns one CN.
此外,我们应该注意,当证书有多个 CN 时,该库只返回一个 CN。
6. Using the LDAP API
6.使用 LDAP API
We can also use the standard LDAP API from the JDK to achieve the same goal:
我们还可以使用 JDK 中的标准 LDAP API 来实现同样的目标:
@Test
void whenUsingLDAPAPI_thenExtractCommonName() throws Exception {
X500Principal principal = certificate.getSubjectX500Principal();
LdapName ldapDN = new LdapName(principal.getName());
List<String> names = new ArrayList<>();
for (Rdn rdn : ldapDN.getRdns()) {
if (rdn.getType().equalsIgnoreCase("cn")) {
String name = rdn.getValue().toString();
names.add(name);
}
}
for (String commonName : names) {
assertEquals("Baeldung", commonName);
}
}
The above code deals with parsing a DN from an X.509 certificate in the context of LDAP. We construct the LdapName object from the string representation of the DN. It’s a way of converting a DN from the context of X.509 certificates into the context of LDAP.
上述代码处理的是在 LDAP 环境中解析 X.509 证书中的 DN。我们根据 DN 的字符串表示构建 LdapName 对象。这是一种将 DN 从 X.509 证书转换到 LDAP 的方法。
Once we have an instance of LdapName, we can easily dissect the DN into its individual components (like CN, OU, O, etc.) using the getRdns() method.
一旦我们有了 LdapName 的实例,我们就可以使用 getRdns() 方法轻松地将 DN 分解为其各个组件(如 CN、OU、O 等)。
7. Conclusion
7.结论
The CN is a very important part of certificates. In the context of SSL/TLS certificates, the CN is used to indicate the domain name associated with the certificate.
CN 是证书的重要组成部分。在 SSL/TLS 证书中,CN 用于表示与证书相关的域名。
In this article, we learned how to extract the CN value of a certificate file using several approaches.
在本文中,我们学习了如何使用几种方法提取证书文件的 CN 值。
As always, code samples can be found over on GitHub.
一如既往,您可以在 GitHub 上找到代码示例。