TLS

Encryption/decryption schemes are of limited use if you have to do all the heavy lifting yourself. The most popular mechanism on the internet to give support for encrypted message passing is currently TLS (Transport Layer Security) which was formerly SSL (Secure Sockets Layer).

In TLS, a client and a server negotiate identity using X.509 certificates. Once this is complete, a secret key is invented between them, and all encryption/decryption is done using this key. The negotiation is relatively slow, but once complete a faster private key mechanism is used.

A server is

  1. /* TLSEchoServer
  2. */
  3. package main
  4. import (
  5. "crypto/rand"
  6. "crypto/tls"
  7. "fmt"
  8. "net"
  9. "os"
  10. "time"
  11. )
  12. func main() {
  13. cert, err := tls.LoadX509KeyPair("jan.newmarch.name.pem", "private.pem")
  14. checkError(err)
  15. config := tls.Config{Certificates: []tls.Certificate{cert}}
  16. now := time.Now()
  17. config.Time = func() time.Time { return now }
  18. config.Rand = rand.Reader
  19. service := "0.0.0.0:1200"
  20. listener, err := tls.Listen("tcp", service, &config)
  21. checkError(err)
  22. fmt.Println("Listening")
  23. for {
  24. conn, err := listener.Accept()
  25. if err != nil {
  26. fmt.Println(err.Error())
  27. continue
  28. }
  29. fmt.Println("Accepted")
  30. go handleClient(conn)
  31. }
  32. }
  33. func handleClient(conn net.Conn) {
  34. defer conn.Close()
  35. var buf [512]byte
  36. for {
  37. fmt.Println("Trying to read")
  38. n, err := conn.Read(buf[0:])
  39. if err != nil {
  40. fmt.Println(err)
  41. }
  42. _, err2 := conn.Write(buf[0:n])
  43. if err2 != nil {
  44. return
  45. }
  46. }
  47. }
  48. func checkError(err error) {
  49. if err != nil {
  50. fmt.Println("Fatal error ", err.Error())
  51. os.Exit(1)
  52. }
  53. }

The server works with the following client:

  1. /* TLSEchoClient
  2. */
  3. package main
  4. import (
  5. "fmt"
  6. "os"
  7. "crypto/tls"
  8. )
  9. func main() {
  10. if len(os.Args) != 2 {
  11. fmt.Println("Usage: ", os.Args[0], "host:port")
  12. os.Exit(1)
  13. }
  14. service := os.Args[1]
  15. conn, err := tls.Dial("tcp", service, nil)
  16. checkError(err)
  17. for n := 0; n < 10; n++ {
  18. fmt.Println("Writing...")
  19. conn.Write([]byte("Hello " + string(n+48)))
  20. var buf [512]byte
  21. n, err := conn.Read(buf[0:])
  22. checkError(err)
  23. fmt.Println(string(buf[0:n]))
  24. }
  25. os.Exit(0)
  26. }
  27. func checkError(err error) {
  28. if err != nil {
  29. fmt.Println("Fatal error ", err.Error())
  30. os.Exit(1)
  31. }
  32. }

Conclusion

Security is a huge area in itself, and in this chapter we have barely touched on it. However, the major concepts have been covered. What has not been stressed is how much security needs to be built into the design phase: security as an afterthought is nearly always a failure.