Harden contract validation, STARTTLS edge cases, and rule output
This commit is contained in:
parent
a925e4f162
commit
fa212f0fae
9 changed files with 104 additions and 39 deletions
|
|
@ -31,6 +31,9 @@ func starttlsXMPP(conn net.Conn, sni, ns string) error {
|
|||
dec := xml.NewDecoder(conn)
|
||||
|
||||
// Read the inbound <stream:stream> opening and its <stream:features>.
|
||||
// A peer that opens with <stream:error/> (or anything other than features)
|
||||
// is not going to advertise STARTTLS: surface that immediately rather
|
||||
// than spinning on tokens until the deadline fires.
|
||||
hasStartTLS := false
|
||||
outer:
|
||||
for {
|
||||
|
|
@ -38,29 +41,38 @@ outer:
|
|||
if err != nil {
|
||||
return fmt.Errorf("read stream features: %w", err)
|
||||
}
|
||||
if se, ok := tok.(xml.StartElement); ok {
|
||||
if se.Name.Local == "features" {
|
||||
// Scan features children.
|
||||
for {
|
||||
t2, err := dec.Token()
|
||||
if err != nil {
|
||||
return fmt.Errorf("read features body: %w", err)
|
||||
se, ok := tok.(xml.StartElement)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch se.Name.Local {
|
||||
case "stream":
|
||||
// Outer <stream:stream> opening. Continue reading children.
|
||||
continue
|
||||
case "features":
|
||||
for {
|
||||
t2, err := dec.Token()
|
||||
if err != nil {
|
||||
return fmt.Errorf("read features body: %w", err)
|
||||
}
|
||||
switch ee := t2.(type) {
|
||||
case xml.StartElement:
|
||||
if ee.Name.Local == "starttls" {
|
||||
hasStartTLS = true
|
||||
}
|
||||
switch ee := t2.(type) {
|
||||
case xml.StartElement:
|
||||
if ee.Name.Local == "starttls" {
|
||||
hasStartTLS = true
|
||||
}
|
||||
if err := dec.Skip(); err != nil {
|
||||
return fmt.Errorf("skip feature %q: %w", ee.Name.Local, err)
|
||||
}
|
||||
case xml.EndElement:
|
||||
if ee.Name.Local == "features" {
|
||||
break outer
|
||||
}
|
||||
if err := dec.Skip(); err != nil {
|
||||
return fmt.Errorf("skip feature %q: %w", ee.Name.Local, err)
|
||||
}
|
||||
case xml.EndElement:
|
||||
if ee.Name.Local == "features" {
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
case "error":
|
||||
return fmt.Errorf("server returned <stream:error/> before features")
|
||||
default:
|
||||
return fmt.Errorf("%w: unexpected element %q before features", errStartTLSNotOffered, se.Name.Local)
|
||||
}
|
||||
}
|
||||
if !hasStartTLS {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue