人与马做网站,网站怎么样做,网站首页新闻模板,网站制作培训中心文章目录 证书的SCT列表验证SCT依赖包加载证书初始化log机构信息离线验证在线验证 证书的SCT列表
浏览器对证书链的合法性检查通过后#xff0c;会再检查服务端证书附件里的SCT列表#xff08;Signed Certificate Timestamp#xff09;#xff1b; 浏览器内置了一批certif… 文章目录 证书的SCT列表验证SCT依赖包加载证书初始化log机构信息离线验证在线验证 证书的SCT列表
浏览器对证书链的合法性检查通过后会再检查服务端证书附件里的SCT列表Signed Certificate Timestamp 浏览器内置了一批certificate transparency log机构的公钥和访问地址如果SCT申明证书在某个log机构注册了但是SCT里的签名通过不了log机构的公钥验证则抛出错误NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED
验证SCT
依赖包
使用github.com/google/certificate-transparency-go工具
import (contextencoding/base64encoding/pemerrorsiolognet/httpostimect github.com/google/certificate-transparency-gogithub.com/google/certificate-transparency-go/ctutilgithub.com/google/certificate-transparency-go/loglist3ctX509 github.com/google/certificate-transparency-go/x509github.com/google/certificate-transparency-go/x509util
)加载证书
假设服务端证书以及签发该证书的上级CA证书已保存为PEM格式的文件
func VerifySCT(certLocation string, issuerLocation string) error {// 服务端证书certByte, err : os.ReadFile(certLocation)if err ! nil {return err}block, _ : pem.Decode(certByte)if block nil || len(block.Bytes) 0 {return errors.New(error decoding certificate)}cert, err : ctX509.ParseCertificate(block.Bytes)if err ! nil {return err}// 上级CAcertByte, _ os.ReadFile(issuerLocation)block, _ pem.Decode(certByte)if block nil || len(block.Bytes) 0 {return errors.New(error decoding issuer CA)}issuer, _ : ctX509.ParseCertificate(block.Bytes)err cert.CheckSignatureFrom(issuer)if err ! nil {log.Printf(证书%s的签名算法是%sCA签名没有验证成功, cert.Subject, cert.SignatureAlgorithm.String())return err}// 生成merkle tree leaf用于验证sct(Signed Certificate Timestamp)merkleLeaf, err : ct.MerkleTreeLeafForEmbeddedSCT([]*ctX509.Certificate{cert, issuer}, 0)if err ! nil {return err}// 获取证书里附带的sct列表sctList, err : x509util.ParseSCTsFromSCTList(cert.SCTList)if err ! nil {log.Printf(ParseCertificate failed %v, err)return err}log.Printf(验证证书%s的SCT列表, cert.Subject)初始化log机构信息
使用和chrome一致的机构列表https://www.gstatic.com/ct/log_list/v3/log_list.json // 获取chrome使用的certificate transparency log机构列表包含机构使用的公钥和查询api地址resp, err : http.DefaultClient.Get(loglist3.LogListURL)if err ! nil {return errors.New(下载certificate transparency log地址列表失败)}defer resp.Body.Close()body, err : io.ReadAll(resp.Body)if err ! nil {return errors.New(下载certificate transparency log地址列表失败)}loglistEntry, _ : loglist3.NewFromJSON(body)logsByHash, _ : ctutil.LogInfoByKeyHash(loglistEntry, http.DefaultClient)离线验证在线验证
logInfo.VerifySCTSignature方法不需要和log机构在线交互是使用已知的log机构公钥对SCT进行离线验证 ctx, cancel : context.WithTimeout(context.Background(), 10*time.Second)defer cancel()for _, sct : range sctList {// 验证sct参考https://github.com/google/certificate-transparency-go/blob/master/ctutil/sctscan/sctscan.golog.Printf(sct signature: %s, %s, base64.StdEncoding.EncodeToString(sct.Signature.Signature), time.Unix(0, int64(sct.Timestamp)*int64(time.Millisecond)).Format(time.RFC3339Nano))logInfo, ok : logsByHash[sct.LogID.KeyID]if !ok {log.Printf(sct key_hash: %s不存在对应certificate transparency log机构, base64.StdEncoding.EncodeToString(sct.LogID.KeyID[:]))continue}log.Printf(颁发sct的certificate transparency log机构是: %s地址%s, 公钥哈希%s, logInfo.Description,logInfo.Client.BaseURI(), base64.StdEncoding.EncodeToString(sct.LogID.KeyID[:]))err logInfo.VerifySCTSignature(*sct, *merkleLeaf)if err ! nil {log.Printf(Verify SCT failed %v, err)continue}log.Println(Verify SCT offline OK)// 线上验证非必须if _, err : logInfo.VerifyInclusionLatest(ctx, *merkleLeaf, sct.Timestamp); err ! nil {sth : logInfo.LastSTH()if sth ! nil {delta : time.Duration(sth.Timestamp-sct.Timestamp) * time.Millisecondif delta logInfo.MMD {// 如果生效时间logInfo.MMD还未到那么机构查询不到该sct的merkle tree leaf信息是正常的log.Printf(SCTs MMD has not passed %d - %d %v, sct.Timestamp, sth.Timestamp, logInfo.MMD)continue}}log.Printf(Failed to verify SCT online: %v, err)} else {log.Println(Verify SCT online OK)}}
每个SCT分别是不同log机构签发的如果一个证书附带的两个SCT是由同一个log机构签发或者SCT列表涉及的log机构合计不足3个浏览器似乎也会报错 目前证书检查通过后chrome的F12里才显示解析的SCT列表ERR_CERTIFICATE_TRANSPARENCY_REQUIRED错误发生时需要使用这个程序来查看SCT列表里是否存在重复注册、注册的log机构数量不足甚至是否无法通过SCT签名检查