Reject invalid status codes

This commit is contained in:
adnano 2020-09-27 19:56:33 -04:00
parent 9f1a38a0dd
commit 73e4ef0689
5 changed files with 21 additions and 12 deletions

View File

@ -15,11 +15,11 @@ import (
// Client errors. // Client errors.
var ( var (
ErrProtocol = errors.New("gemini: protocol error") ErrInvalidURL = errors.New("gemini: invalid URL")
ErrInvalidURL = errors.New("gemini: requested URL is invalid") ErrInvalidResponse = errors.New("gemini: invalid response")
ErrCertificateNotValid = errors.New("gemini: certificate is invalid") ErrInvalidCertificate = errors.New("gemini: invalid certificate")
ErrUnknownCertificate = errors.New("gemini: unknown certificate")
ErrCertificateNotTrusted = errors.New("gemini: certificate is not trusted") ErrCertificateNotTrusted = errors.New("gemini: certificate is not trusted")
ErrCertificateUnknown = errors.New("gemini: certificate is unknown")
) )
// Request represents a Gemini request. // Request represents a Gemini request.
@ -133,11 +133,18 @@ func (resp *Response) read(r *bufio.Reader) error {
} }
resp.Status = status resp.Status = status
// Disregard invalid status codes
const minStatus, maxStatus = 1, 6
statusClass := status / 10
if statusClass < minStatus || statusClass > maxStatus {
return ErrInvalidResponse
}
// Read one space // Read one space
if b, err := r.ReadByte(); err != nil { if b, err := r.ReadByte(); err != nil {
return err return err
} else if b != ' ' { } else if b != ' ' {
return ErrProtocol return ErrInvalidResponse
} }
// Read the meta // Read the meta
@ -149,7 +156,7 @@ func (resp *Response) read(r *bufio.Reader) error {
meta = meta[:len(meta)-1] meta = meta[:len(meta)-1]
// Ensure meta is less than or equal to 1024 bytes // Ensure meta is less than or equal to 1024 bytes
if len(meta) > 1024 { if len(meta) > 1024 {
return ErrProtocol return ErrInvalidResponse
} }
resp.Meta = meta resp.Meta = meta
@ -157,7 +164,7 @@ func (resp *Response) read(r *bufio.Reader) error {
if b, err := r.ReadByte(); err != nil { if b, err := r.ReadByte(); err != nil {
return err return err
} else if b != '\n' { } else if b != '\n' {
return ErrProtocol return ErrInvalidResponse
} }
// Read response body // Read response body
@ -244,11 +251,11 @@ func (c *Client) Send(req *Request) (*Response, error) {
// Read the response // Read the response
resp := &Response{} resp := &Response{}
r := bufio.NewReader(conn) r := bufio.NewReader(conn)
// Store connection information
resp.TLS = conn.ConnectionState()
if err := resp.read(r); err != nil { if err := resp.read(r); err != nil {
return nil, err return nil, err
} }
// Store connection information
resp.TLS = conn.ConnectionState()
return resp, nil return resp, nil
} }

View File

@ -38,6 +38,7 @@ func main() {
// To generate a TLS key pair, run: // To generate a TLS key pair, run:
// //
// go run -tags=example ../cert // go run -tags=example ../cert
//
cert, err := tls.LoadX509KeyPair("examples/client/localhost.crt", "examples/client/localhost.key") cert, err := tls.LoadX509KeyPair("examples/client/localhost.crt", "examples/client/localhost.key")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -28,7 +28,7 @@ func init() {
// Alert the user that the certificate is not trusted // Alert the user that the certificate is not trusted
fmt.Printf("Warning: Certificate for %s is not trusted!\n", hostname) fmt.Printf("Warning: Certificate for %s is not trusted!\n", hostname)
fmt.Println("This could indicate a Man-in-the-Middle attack.") fmt.Println("This could indicate a Man-in-the-Middle attack.")
case gemini.ErrCertificateUnknown: case gemini.ErrUnknownCertificate:
// Prompt the user to trust the certificate // Prompt the user to trust the certificate
trust := trustCertificate(cert) trust := trustCertificate(cert)
switch trust { switch trust {

View File

@ -14,6 +14,7 @@ func main() {
// To generate a TLS key pair, run: // To generate a TLS key pair, run:
// //
// go run -tags=example ../cert // go run -tags=example ../cert
//
cert, err := tls.LoadX509KeyPair("examples/server/localhost.crt", "examples/server/localhost.key") cert, err := tls.LoadX509KeyPair("examples/server/localhost.crt", "examples/server/localhost.key")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -79,7 +79,7 @@ func (k *KnownHosts) AddTemporary(hostname string, cert *x509.Certificate) {
// Lookup looks for the provided certificate in the list of known hosts. // Lookup looks for the provided certificate in the list of known hosts.
// If the hostname is in the list, but the fingerprint differs, // If the hostname is in the list, but the fingerprint differs,
// Lookup returns ErrCertificateNotTrusted. // Lookup returns ErrCertificateNotTrusted.
// If the hostname is not in the list, Lookup returns ErrCertificateUnknown. // If the hostname is not in the list, Lookup returns ErrUnknownCertificate.
// If the certificate is found and the fingerprint matches, error will be nil. // If the certificate is found and the fingerprint matches, error will be nil.
func (k *KnownHosts) Lookup(hostname string, cert *x509.Certificate) error { func (k *KnownHosts) Lookup(hostname string, cert *x509.Certificate) error {
now := time.Now().Unix() now := time.Now().Unix()
@ -99,7 +99,7 @@ func (k *KnownHosts) Lookup(hostname string, cert *x509.Certificate) error {
// Fingerprint does not match // Fingerprint does not match
return ErrCertificateNotTrusted return ErrCertificateNotTrusted
} }
return ErrCertificateUnknown return ErrUnknownCertificate
} }
// Parse parses the provided reader and adds the parsed known hosts to the list. // Parse parses the provided reader and adds the parsed known hosts to the list.