Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom tls.Configs #101

Merged
merged 4 commits into from
Jul 1, 2013

Conversation

lukescott
Copy link
Contributor

This adds the ability to customize the tls.Config object so you can:

  • Specify a custom RootCA (instead of skip verify)
  • Specify a client certificate for authentication w/ or w/out a password

Example of how it would be used:

package main

import (
    "crypto/tls"
    "crypto/x509"
    "database/sql"
    "fmt"
    "github.com/lukescott/mysql"
    "io/ioutil"
    "log"
)

func main() {
    rootCAs := x509.NewCertPool()
    {
        pem, err := ioutil.ReadFile("/path/ca-cert.pem")
        if err != nil {
            log.Fatal(err)
        }
        if ok := rootCAs.AppendCertsFromPEM(pem); !ok {
            log.Fatal("Failed to append PEM.")
        }
    }
    clientCerts := make([]tls.Certificate, 0, 1)
    {
        certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem")
        if err != nil {
            log.Fatal(err)
        }
        clientCerts = append(clientCerts, certs)
    }
    mysql.RegisterTLSConfig("custom", &tls.Config{
        RootCAs:      rootCAs,
        Certificates: clientCerts,
    })
    db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom")
    if err != nil {
        log.Fatal(err)
    }
    var row string
    err = db.QueryRow("SHOW DATABASES").Scan(&row)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%#v\n", row)
}

@lukescott lukescott mentioned this pull request Jun 19, 2013
@ghost ghost assigned julienschmidt Jun 22, 2013
"crypto/tls"
)

type TLSConfig interface {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this interface for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, as you commented on later.

@lukescott
Copy link
Contributor Author

Ok all the changes are made. I'm not very good at writing documentation, but gave it my best shot.

@@ -113,7 +114,7 @@ Possible Parameters are:
* `parseTime`: `parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string`
* `strict`: Enable strict mode. MySQL warnings are treated as errors.
* `timeout`: **Driver** side connection timeout. The value must be a string of decimal numbers, each with optional fraction and a unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*. To set a server side timeout, use the parameter [`wait_timeout`](http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_wait_timeout).
* `tls`: `true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side)
* `tls`: `true` enables TLS / SSL encrypted connection to the server. For other values see [TLS support](#tls-support).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for my delayed response.
Please keep it up here. It is not necessary to make a new section for a single parameter. Just note that you can register your own configurations and refer to the godoc.
Ignore the INFILE section, this will be reworked before the next release.

@julienschmidt
Copy link
Member

LGTM
@arnehormann ?

@arnehormann
Copy link
Member

@julienschmidt LGTM; I'd love to have tests for it, though.
Sorry for the late reaction, I thought it's sufficient if one non-author okays it - which would be you for external contributions in most cases.

@julienschmidt
Copy link
Member

Yes, this is the general case. But I'm more comfortable if another pair of eyes checks this PR to make sure we didn't miss a thing.

// Use the key as a value in the DSN where tls=value.
//
// rootCertPool := x509.NewCertPool()
// {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this one... the extra scopes are a bit confusing since they are not conventional Go-style.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed what?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed the note on this line 😉

@julienschmidt
Copy link
Member

Please replace the TestTLS function in driver_test.go with the following code:

func TestTLS(t *testing.T) {
    tlsTest := func(dbt *DBTest) {
        if err := dbt.db.Ping(); err != nil {
            if err == errNoTLS {
                dbt.Skip("Server does not support TLS")
            } else {
                dbt.Fatalf("Error on Ping: %s", err.Error())
            }
        }

        rows := dbt.mustQuery("SHOW STATUS LIKE 'Ssl_cipher'")

        var variable, value *sql.RawBytes
        for rows.Next() {
            if err := rows.Scan(&variable, &value); err != nil {
                dbt.Fatal(err.Error())
            }

            if value == nil {
                dbt.Fatal("No Cipher")
            }
        }
    }

    runTests(t, dsn+"&tls=skip-verify", tlsTest)

    // Verify that registering / using a custom cfg works
    RegisterTLSConfig("custom-skip-verify", &tls.Config{
        InsecureSkipVerify: true,
    })
    runTests(t, dsn+"&tls=custom-skip-verify", tlsTest)
}

Also add "crypto/tls" to the package imports of driver_test.go

This adds a simple test, that verifies that registering a custom tls.Config works (regardless of the server supports TLS)

@lukescott
Copy link
Contributor Author

Ok, I've made the changes. Tests pass. Here is the diff. Anything else before I make the next commit?

(Scopes removed in example, test added, tls.Config{} changed to &tls.Config{})

...

@julienschmidt
Copy link
Member

No, looks good to me now.
Please commit and wait for @arnehormann to make the final LGTM in order to merge this PR.

@julienschmidt
Copy link
Member

Oh sorry, he already did earlier. Just commit and I merge it

@julienschmidt
Copy link
Member

Thanks a lot!

julienschmidt added a commit that referenced this pull request Jul 1, 2013
Add support for custom tls.Configs
@julienschmidt julienschmidt merged commit 87f2050 into go-sql-driver:master Jul 1, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants