diff --git a/helpers.go b/helpers.go index 485a15e..796d49f 100644 --- a/helpers.go +++ b/helpers.go @@ -114,8 +114,8 @@ type CertInfo struct { SerialNumberParseError error Validity *CertValidity ValidityParseError error - Constraints *BasicConstraints - ConstraintsParseError error + IsCA *bool + IsCAParseError error } func MakeCertInfoFromTBS (tbs *TBSCertificate) *CertInfo { @@ -127,7 +127,7 @@ func MakeCertInfoFromTBS (tbs *TBSCertificate) *CertInfo { info.Issuer, info.IssuerParseError = tbs.ParseIssuer() info.SerialNumber, info.SerialNumberParseError = tbs.ParseSerialNumber() info.Validity, info.ValidityParseError = tbs.ParseValidity() - info.Constraints, info.ConstraintsParseError = tbs.ParseBasicConstraints() + info.IsCA, info.IsCAParseError = tbs.ParseBasicConstraints() return info } @@ -256,7 +256,7 @@ func (info *EntryInfo) HasParseErrors () bool { info.CertInfo.IssuerParseError != nil || info.CertInfo.SerialNumberParseError != nil || info.CertInfo.ValidityParseError != nil || - info.CertInfo.ConstraintsParseError != nil + info.CertInfo.IsCAParseError != nil } func (info *EntryInfo) Fingerprint () string { diff --git a/x509.go b/x509.go index b01da32..58ad15f 100644 --- a/x509.go +++ b/x509.go @@ -29,7 +29,7 @@ type CertValidity struct { NotAfter time.Time } -type BasicConstraints struct { +type basicConstraints struct { IsCA bool `asn1:"optional"` MaxPathLen int `asn1:"optional,default:-1"` } @@ -164,21 +164,39 @@ func (tbs *TBSCertificate) ParseValidity () (*CertValidity, error) { return &validity, nil } -func (tbs *TBSCertificate) ParseBasicConstraints () (*BasicConstraints, error) { - constraintExts := tbs.GetExtension(oidExtensionBasicConstraints) - if len(constraintExts) == 0 { - return nil, nil - } else if len(constraintExts) > 1 { - return nil, fmt.Errorf("Certificate has more than one Basic Constraints extension") +func (tbs *TBSCertificate) ParseBasicConstraints () (*bool, error) { + isCA := false + isNotCA := false + + // Some certs in the wild have multiple BasicConstraints extensions (is there anything + // that CAs haven't screwed up???), so we process all of them and only choke if they + // are contradictory (which has not been observed...yet). + for _, ext := range tbs.GetExtension(oidExtensionBasicConstraints) { + var constraints basicConstraints + if rest, err := asn1.Unmarshal(ext.Value, &constraints); err != nil { + return nil, errors.New("failed to parse Basic Constraints: " + err.Error()) + } else if len(rest) > 0 { + return nil, fmt.Errorf("trailing data after Basic Constraints: %v", rest) + } + + if constraints.IsCA { + isCA = true + } else { + isNotCA = true + } } - var constraints BasicConstraints - if rest, err := asn1.Unmarshal(constraintExts[0].Value, &constraints); err != nil { - return nil, errors.New("failed to parse Basic Constraints: " + err.Error()) - } else if len(rest) > 0 { - return nil, fmt.Errorf("trailing data after Basic Constraints: %v", rest) + if !isCA && !isNotCA { + return nil, nil + } else if isCA && !isNotCA { + trueValue := true + return &trueValue, nil + } else if !isCA && isNotCA { + falseValue := false + return &falseValue, nil + } else { + return nil, fmt.Errorf("Certificate has more than one Basic Constraints extension and they are contradictory") } - return &constraints, nil } func (tbs *TBSCertificate) ParseSerialNumber () (*big.Int, error) {