// A CASet is a set of certificates.
type CASet struct {
- bySubjectKeyId map[string]*x509.Certificate
- byName map[string]*x509.Certificate
+ bySubjectKeyId map[string][]*x509.Certificate
+ byName map[string][]*x509.Certificate
}
func NewCASet() *CASet {
return &CASet{
- make(map[string]*x509.Certificate),
- make(map[string]*x509.Certificate),
+ make(map[string][]*x509.Certificate),
+ make(map[string][]*x509.Certificate),
}
}
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
}
-// FindParent attempts to find the certificate in s which signs the given
-// certificate. If no such certificate can be found, it returns nil.
-func (s *CASet) FindParent(cert *x509.Certificate) (parent *x509.Certificate) {
+// FindVerifiedParent attempts to find the certificate in s which has signed
+// the given certificate. If no such certificate can be found or the signature
+// doesn't match, it returns nil.
+func (s *CASet) FindVerifiedParent(cert *x509.Certificate) (parent *x509.Certificate) {
+ var candidates []*x509.Certificate
+
if len(cert.AuthorityKeyId) > 0 {
- return s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+ candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+ }
+ if len(candidates) == 0 {
+ candidates = s.byName[nameToKey(&cert.Issuer)]
+ }
+
+ for _, c := range candidates {
+ if cert.CheckSignatureFrom(c) == nil {
+ return c
+ }
}
- return s.byName[nameToKey(&cert.Issuer)]
+
+ return nil
+}
+
+// AddCert adds a certificate to the set
+func (s *CASet) AddCert(cert *x509.Certificate) {
+ if len(cert.SubjectKeyId) > 0 {
+ keyId := string(cert.SubjectKeyId)
+ s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], cert)
+ }
+ name := nameToKey(&cert.Subject)
+ s.byName[name] = append(s.byName[name], cert)
}
// SetFromPEM attempts to parse a series of PEM encoded root certificates. It
continue
}
- if len(cert.SubjectKeyId) > 0 {
- s.bySubjectKeyId[string(cert.SubjectKeyId)] = cert
- }
- s.byName[nameToKey(&cert.Subject)] = cert
+ s.AddCert(cert)
ok = true
}
finishedHash.Write(certMsg.marshal())
certs := make([]*x509.Certificate, len(certMsg.certificates))
+ chain := NewCASet()
for i, asn1Data := range certMsg.certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
return os.ErrorString("failed to parse certificate from server: " + err.String())
}
certs[i] = cert
+ chain.AddCert(cert)
}
- for i := 1; i < len(certs); i++ {
- if !certs[i].BasicConstraintsValid || !certs[i].IsCA {
- c.sendAlert(alertBadCertificate)
- return os.ErrorString("intermediate certificate does not have CA bit set")
+ // If we don't have a root CA set configured then anything is accepted.
+ // TODO(rsc): Find certificates for OS X 10.6.
+ for cur := certs[0]; c.config.RootCAs != nil; {
+ parent := c.config.RootCAs.FindVerifiedParent(cur)
+ if parent != nil {
+ break
}
- // KeyUsage status flags are ignored. From Engineering
- // Security, Peter Gutmann:
- // A European government CA marked its signing certificates as
- // being valid for encryption only, but no-one noticed. Another
- // European CA marked its signature keys as not being valid for
- // signatures. A different CA marked its own trusted root
- // certificate as being invalid for certificate signing.
- // Another national CA distributed a certificate to be used to
- // encrypt data for the country’s tax authority that was marked
- // as only being usable for digital signatures but not for
- // encryption. Yet another CA reversed the order of the bit
- // flags in the keyUsage due to confusion over encoding
- // endianness, essentially setting a random keyUsage in
- // certificates that it issued. Another CA created a
- // self-invalidating certificate by adding a certificate policy
- // statement stipulating that the certificate had to be used
- // strictly as specified in the keyUsage, and a keyUsage
- // containing a flag indicating that the RSA encryption key
- // could only be used for Diffie-Hellman key agreement.
- if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
- c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not validate certificate signature: " + err.String())
- }
- }
-
- // TODO(rsc): Find certificates for OS X 10.6.
- if c.config.RootCAs != nil {
- root := c.config.RootCAs.FindParent(certs[len(certs)-1])
- if root == nil {
+ parent = chain.FindVerifiedParent(cur)
+ if parent == nil {
c.sendAlert(alertBadCertificate)
return os.ErrorString("could not find root certificate for chain")
}
- if err := certs[len(certs)-1].CheckSignatureFrom(root); err != nil {
+
+ if !parent.BasicConstraintsValid || !parent.IsCA {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not validate signature from expected root: " + err.String())
+ return os.ErrorString("intermediate certificate does not have CA bit set")
}
+ // KeyUsage status flags are ignored. From Engineering
+ // Security, Peter Gutmann: A European government CA marked its
+ // signing certificates as being valid for encryption only, but
+ // no-one noticed. Another European CA marked its signature
+ // keys as not being valid for signatures. A different CA
+ // marked its own trusted root certificate as being invalid for
+ // certificate signing. Another national CA distributed a
+ // certificate to be used to encrypt data for the country’s tax
+ // authority that was marked as only being usable for digital
+ // signatures but not for encryption. Yet another CA reversed
+ // the order of the bit flags in the keyUsage due to confusion
+ // over encoding endianness, essentially setting a random
+ // keyUsage in certificates that it issued. Another CA created
+ // a self-invalidating certificate by adding a certificate
+ // policy statement stipulating that the certificate had to be
+ // used strictly as specified in the keyUsage, and a keyUsage
+ // containing a flag indicating that the RSA encryption key
+ // could only be used for Diffie-Hellman key agreement.
+
+ cur = parent
}
pub, ok := certs[0].PublicKey.(*rsa.PublicKey)