【Go】解析X509

  • Post author:
  • Post category:其他


解析DER证书

    //读der证书
    derTmp, err := ioutil.ReadFile("123.cer")
	if err != nil {
		fmt.Println("Read file failed")
		return
	}
    //调用x509的接口
	certBodyTmp, err := x509.ParseCertificate(derTmp)
	if err != nil {
		fmt.Println(err)
		return
	}

解析PEM证书

    //先解码,再解析
    certBlock, restBlock := pem.Decode([]byte(pemStr))
	if certBlock == nil {
		fmt.Println(err)
		return
	}
	
	certBody, err := x509.ParseCertificate(certBlock.Bytes)
	if err != nil {
		fmt.Println(err)
		return
	}

测试的时候直接传PEM的数据解码不成功,形式如下

通过读文件或者pem数据中的换行换成\n形式才成功

解析PEM证书链

//递归解码,存到tls.Certificate中
func DecodeChain(chainByteArray []byte, certBuf *tls.Certificate) {
	certDERBlock, restPEMBlock := pem.Decode(chainByteArray)
	if certDERBlock == nil {
		return
	}

	certBuf.Certificate = append(certBuf.Certificate, certDERBlock.Bytes)
	if len(restPEMBlock) != 0 {
		DecodeChain(restPEMBlock, certBuf)
	}
}
    chainsTmp, err := ioutil.ReadFile("chains.pem")
	if err != nil {
		fmt.Println("Read file failed")
		return
	}

	var chainList tls.Certificate
	DecodeChain(chainsTmp, &chainList)
	for _, cert := range chainList.Certificate {
		certTmp, _ := x509.ParseCertificate(cert)
	}

DER转PEM

func CertDerToPem(derData []byte) []byte {
	block := &pem.Block{
		Type:  "CERTIFICATE",
		Bytes: derData,
	}

	return pem.EncodeToMemory(block)
}

验证书

    usrCert, error := getCertBody("C:/Users/xxx/Desktop/baidu.cer")
	middleCert, error := getCertBody("C:/Users/xxx/Desktop/GlobalSign-G2.cer")
	// rootCert, error := getCertBody("C:/Users/xxx/Desktop/GlobalSign-root.cer")

	if error != nil {
		return
	}

	fmt.Printf("%x", usrCert.SerialNumber)
	roots := x509.NewCertPool()
	roots.AddCert(middleCert)
	// roots.AddCert(rootCert)
	opts := x509.VerifyOptions{
		DNSName:       "www.baidu.com",
		Intermediates: roots,
		CurrentTime:   time.Now(),
	}
	chains, error := usrCert.Verify(opts)
	if error != nil {
		fmt.Println("verify error", error.Error())
	}

ca证书只有中级根也能够正常验证,验证成功会返回完整的证书链

解析x509证书项


序列号

serialNumber := fmt.Sprintf("%x", certBody.SerialNumber)


签名算法

signAlg := certBody.SignatureAlgorithm.String()


有效期

certBody.NotBefore.Format("2006-01-02 15:04:05")
certBody.NotAfter.Format("2006-01-02 15:04:05")


公钥算法

//获取算法密钥长度
func GetPubKeyLen(pub interface{}) (int, error) {
	var pubKeyLen int
	var err error
	switch pub := pub.(type) {
	case *rsa.PublicKey:
		pubKeyLen = pub.N.BitLen()
	case *ecdsa.PublicKey:
		pubKeyLen = pub.X.BitLen()
	case ed25519.PublicKey:
		pubKeyLen = 8 * len(pub)
	default:
		pubKeyLen = 0
		err = errors.New("PubKey Type Error")
	}
	return pubKeyLen, err
}
keyLen, ok := GetPubKeyLen(certBody.PublicKey)
if ok == nil {
	encryptAlg := certBody.PublicKeyAlgorithm.String() + fmt.Sprintf("(%d bits)", keyLen)
}


公钥值

//二进制值
publicKeyDer, _ = x509.MarshalPKIXPublicKey(certBody.PublicKey)
//转成16进制
hexString := hex.EncodeToString(publicKeyDer)


sha-1指纹

h := sha1.New()
h.Write(certBody.Raw)
s := hex.EncodeToString(h.Sum(nil))
s1 := strings.ToUpper(s)


sha256指纹

h256 := sha256.New()
h256.Write(certBody.Raw)
s256 := hex.EncodeToString(h256.Sum(nil))
ss := strings.ToUpper(s256)
certInfo.Sha256Fp = ss


扩展密钥用法

func ExtKeyUsageString(arr []x509.ExtKeyUsage) []string {
	var extArr []string
	for i := 0; i < len(arr); i++ {
		ext := arr[i]
		// var extStr string
		switch ext {
		case x509.ExtKeyUsageServerAuth:
			extArr = append(extArr, "Server Auth")
		case x509.ExtKeyUsageClientAuth:
			extArr = append(extArr, "Client Auth")
		case x509.ExtKeyUsageCodeSigning:
			extArr = append(extArr, "Code Signing")
		case x509.ExtKeyUsageEmailProtection:
			extArr = append(extArr, "Email Protection")
		case x509.ExtKeyUsageIPSECEndSystem:
			extArr = append(extArr, "IPSEC End System")
		case x509.ExtKeyUsageIPSECTunnel:
			extArr = append(extArr, "IPSEC Tunnel")
		case x509.ExtKeyUsageIPSECUser:
			extArr = append(extArr, "IPSEC User")
		case x509.ExtKeyUsageTimeStamping:
			extArr = append(extArr, "TimeStamping")
		case x509.ExtKeyUsageOCSPSigning:
			extArr = append(extArr, "OCSP Signing")
		case x509.ExtKeyUsageMicrosoftServerGatedCrypto:
			extArr = append(extArr, "Microsoft Server Gated Crypto")
		case x509.ExtKeyUsageNetscapeServerGatedCrypto:
			extArr = append(extArr, "Netscape Server Gated Crypto")
		case x509.ExtKeyUsageMicrosoftCommercialCodeSigning:
			extArr = append(extArr, "Microsoft Commercial Code Signing")
		case x509.ExtKeyUsageMicrosoftKernelCodeSigning:
			extArr = append(extArr, "Microsoft Kernel Code Signing")
		}
	}
	return extArr
}
extKeyUsageList := ExtKeyUsageString(certBody.ExtKeyUsage)


ocsp地址

ocspUrl := certBody.OCSPServer


颁发者机构信息访问地址

caUrl := certBody.IssuingCertificateURL


crl地址

crlUrl := certBody.CRLDistributionPoints


其他扩展项

exts := certBody.Extensions
for i := 0; i < len(exts); i++ {
	ext := exts[i]
	//证书透明sct
	if ext.Id.String() == "1.3.6.1.4.1.11129.2.4.2" {
		certSct := ext.Value
	}
}

结语

x509库解析证书目前无法解析SM2证书,SM2证书验证也验不了,关于SM2证书的操作后续再做进一步介绍



版权声明:本文为a137748099原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。