这个 Let's Encrypt CAA 错误发生了什么?

这个 Let's Encrypt CAA 错误发生了什么?

最近,Let's Encrypt 分享了他们系统中发生的一个错误,该错误导致其客户端出现证书问题。他们这样描述这个错误:

错误:当证书请求包含 N 个需要重新检查 CAA 的域名时,Boulder 会选择一个域名并检查 N 次。这在实践中意味着,如果订户在时间 X 验证了域名,并且该域名在时间 X 的 CAA 记录允许 Let's Encrypt 颁发证书,则该订户将能够在 X+30 天内颁发包含该域名的证书,即使后来有人在该域名上安装了禁止 Let's Encrypt 颁发证书的 CAA 记录。

这是否意味着当用户有多个域名需要 CA 重新检查时,Let's Encrypt 只会检查第一个域名?问题是否在于证书颁发给不属于获得证书的用户的域名?

答案1

Let's Encrypt 根据该漏洞颁发了安全性较低的证书。这更像是一种竞争条件,而不是其他原因。

A加拿大航空协会记录是可选的 DNS 记录,用于限制哪些证书提供商可以为域颁发证书。因此,如果订户在某个时间验证域名,X并且该域的 CAA 记录允许在订户验证其域期间颁发 Let's Encrypt 证书,则订户将有 30 天的时间(从验证日期起)颁发有效证书。因此,如果有人后来添加了 CAA 记录,禁止在 X + 30 天之间的任何时间颁发 LE 证书,则订户将能够忽略 CAA 记录颁发证书。

如果你看看公共关系NewAuthorizationSchema有这个错误,这是在产品中启用功能标志时首次触发它的地方。

问题代码是常见的错误在 Go 中,查看 boulder-ra 的相关代码:

// authz2ModelMapToPB converts a mapping of domain name to authz2Models into a
// protobuf authorizations map
func authz2ModelMapToPB(m map[string]authz2Model) (*sapb.Authorizations, error) {
    resp := &sapb.Authorizations{}
    for k, v := range m {
        // Make a copy of k because it will be reassigned with each loop.
        kCopy := k
        authzPB, err := modelToAuthzPB(&v)
        if err != nil {
            return nil, err
        }
        resp.Authz = append(resp.Authz, &sapb.Authorizations_MapElement{Domain: &kCopy, Authz: authzPB})
    }
    return resp, nil
}

问题在于:引用循环迭代器变量,它们未能v正确处理第二个循环迭代器变量。

反过来,没有考虑这个函数中的两个重要字段IdentifierValueRegistrationID

func modelToAuthzPB(am *authzModel) (*corepb.Authorization, error) {
    expires := am.Expires.UTC().UnixNano()
    id := fmt.Sprintf("%d", am.ID)
    status := uintToStatus[am.Status]
    pb := &corepb.Authorization{
        Id: &id,
        Status: &status,
        Identifier: &am.IdentifierValue,
        RegistrationID: &am.RegistrationID,
        Expires: &expires,
    }

博尔德(特别是 boulder-ra)确定给定的 FQDN 需要 CAA 重新检查,并使用授权对象中的标识符字段,由于上述提交,该字段不正确。因此,标识符字段的处理方式对于单个映射中的所有值都是相同的。因此,例如,如果您有多个需要 CAA 重新检查的授权,boulder-ra 将仅重新检查一个 FQDN,而不会重新检查其他 FQDN。

确实是个糟糕的虫子。

相关内容