如何验证证书链的签出关系

CodingCode · · 2816 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

如何验证证书链的签出关系

在证书链中,通常由根CA证书,签出中间CA证书,再签出服务证书。这是一个签出链关系:
Root CA -> Intermediate CA1 -> Intermediate CA2 -> ... Intermediate CAn -> Server Certificate

那么如何验证谁是谁的签出关系呢,意思就是验证一个证书是由谁签发的。
通常我们拿到一个完整服务端证书的时候会包含:

  1. certificate.pem // 证书PEM
  2. key.pem // 私钥PEM
  3. ca-chain.pem // CA PEM

ca-chain.pem里面可能包含多个CA证书,如何找到直接签出那个CA证书呢。

我们查看证书的一般内容:

$ $ openssl x509 -text -noout -in cert.pem
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN=<cn>, OUT=<ou>, O=<o>, L=<l>, ST=<st>, C=<c>
        Validity
            Not Before: Jun 23 00:13:00 2020 GMT
            Not After : Jun 23 00:18:00 2023 GMT
        Subject: CN=<cn1>, OUT=<ou1>, O=<o>, L=<l>, ST=<st>, C=<c>
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub: 
                    04:f5:XXXX:aa:a9:
                    b3:6d:XXXX:95:1f:
                    30:70:XXXX:44:19:
                    70:e5:XXXX:fb:54:
                    b1:8a:e8:be:bf
                ASN1 OID: prime256v1
                NIST CURVE: P-256
    ...
    Signature Algorithm: ecdsa-with-SHA256
         30:45:XXXX:c3:e8:
         1a:54:XXXX:01:e1:
         55:02:XXXX:bb:b2:
         45:af:XXXX:d1:d3

有几个信息:

  1. Issuer:就是谁签发的,签发者的Subject。
  2. Subject:当前证书的Subject。
  3. Public-Key:证书包含的public key。

这里Issuer就明确表明了当前证书是由谁签发的,那我们去找ca-chain里面的所有证书,挨个遍历找出其Subject和这个一样,那么就说明是签发证书。

理论上是这样的,但是Subject只是包含文本信息,用户可以篡改伪造,只要是同名Subject就可以啦。所以这个字段只是便于肉眼辨识使用,真正使用验证的是signature信息。

在前面证书内容中,最后我们看到有Signature Algorithm域,它的值就是签出证书的signature,这个签名是根据签出证书的内容生成的,只有签出证书本身才能得出这个signature。所以我们需要对照CA证书,生成他的signature值,然后和服务端证书里的这个域值进行比较,如果相当就说明是签出证书。

这个算法比较复杂,不细究了,golang里面提供了函数可以直接调用:
func (c *Certificate) CheckSignatureFrom(parent *Certificate) error

举例:

package main

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

func loadCertificate(pemFile string) (*x509.Certificate, error) {
    certBuff, err := ioutil.ReadFile(pemFile)
    if err != nil {
        fmt.Printf("ERROR: failed to read keystore file: %s, error: %s\n", pemFile, err)
        return nil, err
    }

    block, _ := pem.Decode(certBuff)
    if block == nil {
        fmt.Printf("ERROR: block of decoded private key is nil\n")
        return nil, err
    }

    cert, err := x509.ParseCertificate(block.Bytes)
    if err != nil {
        fmt.Printf("ERROR: failed get ECDSA private key, error: %v\n", err)
        return nil, err
    }

    return cert, nil
}

func main() {
    cert, err   := loadCertificate(os.Args[1])
    if err != nil {
        fmt.Printf("ERROR: failed to load cert, error: %v\n", err)
        return
    }
    issuer, err := loadCertificate(os.Args[2])
    if err != nil {
        fmt.Printf("ERROR: failed to load issuer, error: %v\n", err)
        return
    }
    err = cert.CheckSignatureFrom(issuer)
    if err != nil {
        fmt.Printf("ERROR: verify failed, error: %v\n", err)
        return
    }
    fmt.Printf("cert   subject: %s\n", cert.Subject)
    fmt.Printf("cert   issuer : %s\n", cert.Issuer)
    fmt.Printf("issuer Subject: %s\n", issuer.Subject)
}

输入:go build test.go && ./test cert.pem ca.pem
验证ca.pem是不是cert.pem的直接签出证书。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:CodingCode

查看原文:如何验证证书链的签出关系

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2816 次点击  ∙  1 赞  
加入收藏 微博
1 回复  |  直到 2022-04-29 17:00:27
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传