Simple Golang HTTPS/TLS Examples https://git.io/vSvsI

https://gist.github.com/denji/12b3a568f092ab951456

Generate private key (.key)
  1. # Key considerations for algorithm "RSA" ≥ 2048-bit
  2. openssl genrsa -out server.key 2048
  3. # Key considerations for algorithm "ECDSA" ≥ secp384r1
  4. # List ECDSA the supported curves (openssl ecparam -list_curves)
  5. openssl ecparam -genkey -name secp384r1 -out server.key
Generation of self-signed(x509) public key (PEM-encodings .pem|.crt) based on the private (.key)
  1. openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650

Simple Golang HTTPS/TLS Server

  1. package main
  2. import (
  3. // "fmt"
  4. // "io"
  5. "net/http"
  6. "log"
  7. )
  8. func HelloServer(w http.ResponseWriter, req *http.Request) {
  9. w.Header().Set("Content-Type", "text/plain")
  10. w.Write([]byte("This is an example server.\n"))
  11. // fmt.Fprintf(w, "This is an example server.\n")
  12. // io.WriteString(w, "This is an example server.\n")
  13. }
  14. func main() {
  15. http.HandleFunc("/hello", HelloServer)
  16. err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
  17. if err != nil {
  18. log.Fatal("ListenAndServe: ", err)
  19. }
  20. }

Hint: visit, please do not forget to use https begins, otherwise chrome will download a file as follows:

  1. $ curl -sL https://localhost:443 | xxd
  2. 0000000: 1503 0100 0202 0a .......

TLS (transport layer security) — Server

  1. package main
  2. import (
  3. "log"
  4. "crypto/tls"
  5. "net"
  6. "bufio"
  7. )
  8. func main() {
  9. log.SetFlags(log.Lshortfile)
  10. cer, err := tls.LoadX509KeyPair("server.crt", "server.key")
  11. if err != nil {
  12. log.Println(err)
  13. return
  14. }
  15. config := &tls.Config{Certificates: []tls.Certificate{cer}}
  16. ln, err := tls.Listen("tcp", ":443", config)
  17. if err != nil {
  18. log.Println(err)
  19. return
  20. }
  21. defer ln.Close()
  22. for {
  23. conn, err := ln.Accept()
  24. if err != nil {
  25. log.Println(err)
  26. continue
  27. }
  28. go handleConnection(conn)
  29. }
  30. }
  31. func handleConnection(conn net.Conn) {
  32. defer conn.Close()
  33. r := bufio.NewReader(conn)
  34. for {
  35. msg, err := r.ReadString('\n')
  36. if err != nil {
  37. log.Println(err)
  38. return
  39. }
  40. println(msg)
  41. n, err := conn.Write([]byte("world\n"))
  42. if err != nil {
  43. log.Println(n, err)
  44. return
  45. }
  46. }
  47. }

TLS (transport layer security) — Client

  1. package main
  2. import (
  3. "log"
  4. "crypto/tls"
  5. )
  6. func main() {
  7. log.SetFlags(log.Lshortfile)
  8. conf := &tls.Config{
  9. //InsecureSkipVerify: true,
  10. }
  11. conn, err := tls.Dial("tcp", "127.0.0.1:443", conf)
  12. if err != nil {
  13. log.Println(err)
  14. return
  15. }
  16. defer conn.Close()
  17. n, err := conn.Write([]byte("hello\n"))
  18. if err != nil {
  19. log.Println(n, err)
  20. return
  21. }
  22. buf := make([]byte, 100)
  23. n, err = conn.Read(buf)
  24. if err != nil {
  25. log.Println(n, err)
  26. return
  27. }
  28. println(string(buf[:n]))
  29. }
Perfect SSL Labs Score with Go
  1. package main
  2. import (
  3. "crypto/tls"
  4. "log"
  5. "net/http"
  6. )
  7. func main() {
  8. mux := http.NewServeMux()
  9. mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
  10. w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
  11. w.Write([]byte("This is an example server.\n"))
  12. })
  13. cfg := &tls.Config{
  14. MinVersion: tls.VersionTLS12,
  15. CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
  16. PreferServerCipherSuites: true,
  17. CipherSuites: []uint16{
  18. tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
  19. tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
  20. tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
  21. tls.TLS_RSA_WITH_AES_256_CBC_SHA,
  22. },
  23. }
  24. srv := &http.Server{
  25. Addr: ":443",
  26. Handler: mux,
  27. TLSConfig: cfg,
  28. TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
  29. }
  30. log.Fatal(srv.ListenAndServeTLS("tls.crt", "tls.key"))
  31. }

Generation of self-sign a certificate with a private (.key) and public key (PEM-encodings .pem|.crt) in one command:

  1. # ECDSA recommendation key ≥ secp384r1
  2. # List ECDSA the supported curves (openssl ecparam -list_curves)
  3. openssl req -x509 -nodes -newkey ec:secp384r1 -keyout server.ecdsa.key -out server.ecdsa.crt -days 3650
  4. # openssl req -x509 -nodes -newkey ec:<(openssl ecparam -name secp384r1) -keyout server.ecdsa.key -out server.ecdsa.crt -days 3650
  5. # -pkeyopt ec_paramgen_curve:… / ec:<(openssl ecparam -name …) / -newkey ec:…
  6. ln -sf server.ecdsa.key server.key
  7. ln -sf server.ecdsa.crt server.crt
  8. # RSA recommendation key ≥ 2048-bit
  9. openssl req -x509 -nodes -newkey rsa:2048 -keyout server.rsa.key -out server.rsa.crt -days 3650
  10. ln -sf server.rsa.key server.key
  11. ln -sf server.rsa.crt server.crt
  • .crt — Alternate synonymous most common among *nix systems .pem (pubkey).
  • .csr — Certficate Signing Requests (synonymous most common among *nix systems).
  • .cer — Microsoft alternate form of .crt, you can use MS to convert .crt to .cer (DER encoded .cer, or base64[PEM] encoded .cer).
  • .pem = The PEM extension is used for different types of X.509v3 files which contain ASCII (Base64) armored data prefixed with a «—– BEGIN …» line. These files may also bear the cer or the crt extension.
  • .der — The DER extension is used for binary DER encoded certificates.

Generating the Certficate Signing Request

  1. openssl req -new -sha256 -key server.key -out server.csr
  2. openssl x509 -req -sha256 -in server.csr -signkey server.key -out server.crt -days 3650

ECDSA & RSA — FAQ

  • Validate the elliptic curve parameters -check
  • List “ECDSA” the supported curves openssl ecparam -list_curves
  • Encoding to explicit “ECDSA” -param_enc explicit
  • Conversion form to compressed “ECDSA” -conv_form compressed
  • “EC” parameters and a private key -genkey

CA Bundle Path

Distro Package Path to CA
Fedora, RHEL, CentOS ca-certificates /etc/pki/tls/certs/ca-bundle.crt
Debian, Ubuntu, Gentoo, Arch Linux ca-certificates /etc/ssl/certs/ca-certificates.crt
SUSE, openSUSE ca-certificates /etc/ssl/ca-bundle.pem
FreeBSD ca_root_nss /usr/local/share/certs/ca-root-nss.crt
Cygwin - /usr/ssl/certs/ca-bundle.crt
macOS (MacPorts) curl-ca-bundle /opt/local/share/curl/curl-ca-bundle.crt
Default cURL CA bunde path (without —with-ca-bundle option) /usr/local/share/curl/curl-ca-bundle.crt
Really old RedHat? /usr/share/ssl/certs/ca-bundle.crt

Instead of skipping insecure certificates which could expose your service to MITM attacks, you can create a client that accepts your self-signed certificate:

  1. func main() {
  2. rootPEM := `-----BEGIN CERTIFICATE-----
  3. MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
  4. MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
  5. YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
  6. EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
  7. bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
  8. AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
  9. VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
  10. h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
  11. ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
  12. EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
  13. DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
  14. qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
  15. VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
  16. K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
  17. KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
  18. ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
  19. BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
  20. /iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
  21. zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
  22. HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
  23. WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
  24. yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
  25. -----END CERTIFICATE-----`
  26. roots := x509.NewCertPool()
  27. ok := roots.AppendCertsFromPEM([]byte(rootPEM))
  28. if !ok {
  29. panic("failed to parse root certificate")
  30. }
  31. tlsConf := &tls.Config{RootCAs: roots}
  32. tr := &http.Transport{TLSClientConfig: tlsConf}
  33. client := &http.Client{Transport: tr}
  34. conn, err := client.Dial("tcp", "127.0.0.1:8000")
  35. if err != nil {
  36. log.Println(err)
  37. return
  38. }
  39. defer conn.Close()
  40. ...
  41. }

Kudos for examples!


@c3mb0 With your code I get:

  1. --- FAIL: TestCheckinHandlerPass (0.00s) rest_test.go:88: Get https://localhost:53024/checkin/1480705188/samplegmail: x509: certificate is valid for SignedName, not localhost

Where “SignedName” represents the name I used when self-signing the certificate with the command denji shared.

EDIT: For posterity, to fix this issue, when generating the certificate for the server and it asks for “FQDN or Name” do not put your name there. FQDN stands for “Fully Qualified Domain Name” so if there’s a mismatch then Go will complain (correctly). Instead I’ve put “localhost” the second time around and it’s working beautifully now. Testing it easy and don’t have to rely on InsecureSkipVerify.


Thanks @seantcanavan after changing the FQDN to localhost it worked
In order to clarify I am attaching the modified client code I used to connect with the server example

  1. package main
  2. import (
  3. "crypto/tls"
  4. "crypto/x509"
  5. "io/ioutil"
  6. "log"
  7. )
  8. func main() {
  9. log.SetFlags(log.Lshortfile)
  10. cert, err := ioutil.ReadFile("server.crt")
  11. if err != nil {
  12. log.Fatalf("Couldn't load file", err)
  13. }
  14. certPool := x509.NewCertPool()
  15. certPool.AppendCertsFromPEM(cert)
  16. conf := &tls.Config{
  17. RootCAs: certPool,
  18. }
  19. conn, err := tls.Dial("tcp", "localhost:443", conf)
  20. if err != nil {
  21. log.Println(err)
  22. return
  23. }
  24. defer conn.Close()
  25. n, err := conn.Write([]byte("hello\n"))
  26. if err != nil {
  27. log.Println(n, err)
  28. return
  29. }
  30. buf := make([]byte, 100)
  31. n, err = conn.Read(buf)
  32. if err != nil {
  33. log.Println(n, err)
  34. return
  35. }
  36. println(string(buf[:n]))
  37. }
ft_authoradmin  ft_create_time2018-03-28 10:22
 ft_update_time2018-03-28 10:25