How to get CN from a certificate in Golang

huangapple go评论86阅读模式
英文:

How to get CN from a certificate in Golang

问题

在Golang中,有几种方法可以从X509证书中提取CN(通用名称)。

一种方法是使用crypto/x509包来解析证书并获取主题信息。以下是一个示例代码:

package main

import (
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"log"
)

func getCNFromCertificate(certPath string) (string, error) {
	// 读取证书文件
	certBytes, err := ioutil.ReadFile(certPath)
	if err != nil {
		return "", err
	}

	// 解码PEM格式的证书
	block, _ := pem.Decode(certBytes)
	if block == nil {
		return "", fmt.Errorf("failed to decode PEM certificate")
	}

	// 解析X509证书
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return "", err
	}

	// 获取通用名称
	commonName := cert.Subject.CommonName

	return commonName, nil
}

func main() {
	certPath := "path/to/certificate.pem"
	commonName, err := getCNFromCertificate(certPath)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Common Name:", commonName)
}

另一种方法是使用第三方包,例如github.com/fullsailor/pkcs7。这个包提供了更高级的功能,可以处理PKCS#7格式的证书。以下是一个示例代码:

package main

import (
	"fmt"
	"log"

	"github.com/fullsailor/pkcs7"
)

func getCNFromCertificate(certPath string) (string, error) {
	// 解析PKCS#7格式的证书
	p7, err := pkcs7.Parse(certPath)
	if err != nil {
		return "", err
	}

	// 获取第一个证书
	cert := p7.Certificates[0]

	// 获取通用名称
	commonName := cert.Subject.CommonName

	return commonName, nil
}

func main() {
	certPath := "path/to/certificate.p7"
	commonName, err := getCNFromCertificate(certPath)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Common Name:", commonName)
}

这些示例代码可以帮助你从证书中提取CN。你可以根据自己的需求选择其中一种方法来实现。希望对你有帮助!

英文:

Is there any way to extract CN from X509Certificate in Golang.

Previously we did something like this in Java.

private String getCNFromCertificate() throws InvalidNameException, CertificateException, IOException {
      X509Certificate certificate = getCert(DeploymentConfiguration.getPemCertPath().get());
      String commonName = new LdapName(certificate.getSubjectX500Principal().getName()).getRdns().stream()
              .filter(i -> i.getType().equalsIgnoreCase("CN")).findFirst().get().getValue().toString();
        return commonName;
}

Are there any packages in Golang which can do similar task. Or what could be better alternative to extract CN from Certificate in Golang.

Thank you in advance.

答案1

得分: 1

如何加载和解析公共证书的要点:

bs, err := os.ReadFile("/tmp/google.crt")  // 处理错误

block, _ := pem.Decode(bs)
if block == nil {
    log.Fatal("无法解析包含公钥的PEM块")
}

cert, err := x509.ParseCertificate(block.Bytes) // 处理错误

log.Printf("主题:   %q", cert.Subject)

// 主题:   "CN=*.google.com"

警告`go 1.15`使用[CN存储主机名已被弃用](https://go.dev/doc/go1.15#commonname):

> 默认情况下已禁用将X.509证书上的CommonName字段视为主机名的旧行为当不存在Subject Alternative Names时可以通过将值x509ignoreCN=0添加到GODEBUG环境变量中临时重新启用

如果要在证书中查找主机名或主机名通配符),应使用`SAN`Subject Alternative Names部分其中有一个`DNS`部分这在[x509.Certificate](https://pkg.go.dev/crypto/x509#Certificate)结构的`DNSNames`字段中捕获:

log.Printf("DNS名称: %+v", cert.DNSNames)

// DNS名称: [*.google.com *.appengine.google.com *.bdn.dev *.origin-test.bdn.dev *.cloud.google.com ...

---
[Playground示例](https://go.dev/play/p/g7gKzfLw-Gn)
英文:

The gist of how to load & parse a public cert:

bs, err := os.ReadFile("/tmp/google.crt")  // handle error

block, _ := pem.Decode(bs)
if block == nil {
	log.Fatal("failed to parse PEM block containing the public key")
}

cert, err := x509.ParseCertificate(block.Bytes) // handle error

log.Printf("Subject:   %q", cert.Subject)

// Subject:   "CN=*.google.com"

Warning: since go 1.15 the use of CN to store hostnames is now deprecated:

> The deprecated, legacy behavior of treating the CommonName field on
> X.509 certificates as a host name when no Subject Alternative Names
> are present is now disabled by default. It can be temporarily
> re-enabled by adding the value x509ignoreCN=0 to the GODEBUG
> environment variable.

If you want to find a hostname (or hostname wildcard) within a certification, one should use the SAN (Subject Alternative Names) section - where there is a DNS section. This is captured in the DNSNames field of the x509.Certificate struct:

log.Printf("DNS names: %+v", cert.DNSNames)

// DNS names: [*.google.com *.appengine.google.com *.bdn.dev *.origin-test.bdn.dev *.cloud.google.com ...

Playground Example

答案2

得分: 0

问题的形式不正确,我认为:在X.509证书中没有"CN"这样的东西。CN是"Common Name"的缩写,是在X.509 PKI中用来指代实体的一种形式。你可能想要的是证书的"Subject"字段,也就是该证书所颁发给的实体。

如果是这样,你需要使用x509.CertificateSubject字段,它是一个特殊的复合数据类型,包含了CommonName等信息。

参考这个链接快速了解CN在实体命名中的作用。

crypto/x509是一个库包(即Go标准库提供的)。

英文:

The question is ill-formed, I tink: there's no such thing as "CN" in an X.509 certificate. CN is an abbreviation for "Common Name", which is one form of referring to entities in the X.509 PKI. What you're probably after is the "Subject" field of a certificate—that is, the entity who that certificate was issued for.

If so, you need the Subject field of x509.Certificate, which is a special compound data type containing CommonName, among other things.

See this for a quick overview of what place the CN takes in naming an entity.

The crypto/x509 is a stock package (that is, provided by the Go's standard library).

huangapple
  • 本文由 发表于 2022年10月1日 00:25:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/73911559.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定