
本文提供一个简洁、可运行的 go 示例,演示如何读取 pem 编码的 x.509 证书文件,解码为 der 格式,解析为 *x509.certificate 对象,并安全输出其关键属性(如主题、dns 名称、邮箱、ip 地址等)。
本文提供一个简洁、可运行的 go 示例,演示如何读取 pem 编码的 x.509 证书文件,解码为 der 格式,解析为 *x509.certificate 对象,并安全输出其关键属性(如主题、dns 名称、邮箱、ip 地址等)。
在 Go 中解析 PEM 格式的 X.509 证书需分两步:首先使用 encoding/pem 解包 PEM 容器,提取原始 DER 字节;再用 crypto/x509.ParseCertificate 将 DER 数据反序列化为结构化证书对象。注意:一个 PEM 文件可能包含多个证书(例如证书链),因此需循环解码所有 CERTIFICATE 类型的 block。
以下是完整、现代(适配 Go 1.16+)的示例代码:
package main
import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
"os"
)
func main() {
if len(os.Args) ")
}
certFile := os.Args[1]
certPEMData, err := ioutil.ReadFile(certFile)
if err != nil {
log.Fatalf("failed to read file %s: %v", certFile, err)
}
var blocks [][]byte
for len(certPEMData) > 0 {
var block *pem.Block
block, certPEMData = pem.Decode(certPEMData)
if block == nil {
break // no more PEM blocks
}
if block.Type == "CERTIFICATE" {
blocks = append(blocks, block.Bytes)
}
}
if len(blocks) == 0 {
log.Fatal("no CERTIFICATE blocks found in PEM file")
}
for i, derBytes := range blocks {
cert, err := x509.ParseCertificate(derBytes)
if err != nil {
log.Printf("warning: failed to parse certificate #%d: %v", i+1, err)
continue
}
fmt.Printf("=== Certificate #%d ===\n", i+1)
fmt.Printf("Subject: %s\n", cert.Subject)
fmt.Printf("Issuer: %s\n", cert.Issuer)
fmt.Printf("Serial Number: %x\n", cert.SerialNumber)
fmt.Printf("Not Before: %s\n", cert.NotBefore)
fmt.Printf("Not After: %s\n", cert.NotAfter)
fmt.Printf("DNS Names: %v\n", cert.DNSNames)
fmt.Printf("Email Addresses: %v\n", cert.EmailAddresses)
fmt.Printf("IP Addresses: %v\n", cert.IPAddresses)
fmt.Printf("URIs: %v\n", cert.URIs)
fmt.Println()
}
}
? 注意事项:
- ioutil.ReadFile 在 Go 1.16+ 中已标记为弃用,生产环境建议改用 os.ReadFile(仅需将 ioutil.ReadFile 替换为 os.ReadFile,其余不变);
- pem.Decode 每次只处理一个 block,需循环调用直至返回 nil;
- x509.ParseCertificate 仅支持单个 DER 编码的证书;若需解析私钥或 CSR,请分别使用 x509.ParsePKCS1PrivateKey、x509.ParsePKCS8PrivateKey 或 x509.ParseCertificateRequest;
- 主题(cert.Subject)是 pkix.Name 类型,其字符串表示已格式化为 RFC 2253 风格(如 CN=example.com,O=Acme Inc),如需字段级访问,可直接读取 cert.Subject.CommonName、cert.Subject.Organization 等字段。
该方案轻量、无外部依赖,适用于证书调试、CI/CD 中的合规性检查或 TLS 配置验证等场景。











