func main() { // Load server key. serverKey, err := libtrust.LoadKeyFile(privateKeyFilename) if err != nil { log.Fatal(err) } // Generate server certificate. selfSignedServerCert, err := libtrust.GenerateSelfSignedServerCert( serverKey, []string{"localhost"}, []net.IP{net.ParseIP("127.0.0.1")}, ) if err != nil { log.Fatal(err) } // Load authorized client keys. authorizedClients, err := libtrust.LoadKeySetFile(authorizedClientsFilename) if err != nil { log.Fatal(err) } // Create CA pool using trusted client keys. caPool, err := libtrust.GenerateCACertPool(serverKey, authorizedClients) if err != nil { log.Fatal(err) } // Create TLS config, requiring client certificates. tlsConfig := &tls.Config{ Certificates: []tls.Certificate{ tls.Certificate{ Certificate: [][]byte{selfSignedServerCert.Raw}, PrivateKey: serverKey.CryptoPrivateKey(), Leaf: selfSignedServerCert, }, }, ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: caPool, } // Create HTTP server with simple request handler. server := &http.Server{ Addr: serverAddress, Handler: http.HandlerFunc(requestHandler), } // Listen and server HTTPS using the libtrust TLS config. listener, err := net.Listen("tcp", server.Addr) if err != nil { log.Fatal(err) } tlsListener := tls.NewListener(listener, tlsConfig) server.Serve(tlsListener) }
// RegisterTLSConfig registers a tls configuration to manager // such that any changes to the keys may be reflected in // the tls client CA pool func (c *ClientKeyManager) RegisterTLSConfig(tlsConfig *tls.Config) error { c.clientLock.RLock() certPool, err := libtrust.GenerateCACertPool(c.key, c.clients) if err != nil { return fmt.Errorf("CA pool generation error: %s", err) } c.clientLock.RUnlock() tlsConfig.ClientCAs = certPool c.configLock.Lock() c.configs = append(c.configs, tlsConfig) c.configLock.Unlock() return nil }
// NewIdentityAuthTLSConfig creates a tls.Config for the client to use for // libtrust identity authentication func NewIdentityAuthTLSConfig(trustKey libtrust.PrivateKey, knownHostsPath, proto, addr string) (*tls.Config, error) { tlsConfig := createTLSConfig() // Load known hosts knownHosts, err := libtrust.LoadKeySetFile(knownHostsPath) if err != nil { return nil, fmt.Errorf("Could not load trusted hosts file: %s", err) } // Generate CA pool from known hosts allowedHosts, err := libtrust.FilterByHosts(knownHosts, addr, false) if err != nil { return nil, fmt.Errorf("Error filtering hosts: %s", err) } certPool, err := libtrust.GenerateCACertPool(trustKey, allowedHosts) if err != nil { return nil, fmt.Errorf("Could not create CA pool: %s", err) } tlsConfig.ServerName = "docker" tlsConfig.RootCAs = certPool // Generate client cert from trust key x509Cert, err := libtrust.GenerateSelfSignedClientCert(trustKey) if err != nil { return nil, fmt.Errorf("Certificate generation error: %s", err) } tlsConfig.Certificates = []tls.Certificate{{ Certificate: [][]byte{x509Cert.Raw}, PrivateKey: trustKey.CryptoPrivateKey(), Leaf: x509Cert, }} // Connect to server to see if it is a known host tlsConfig.InsecureSkipVerify = true testConn, err := tls.Dial(proto, addr, tlsConfig) if err != nil { return nil, fmt.Errorf("TLS Handshake error: %s", err) } opts := x509.VerifyOptions{ Roots: tlsConfig.RootCAs, CurrentTime: time.Now(), DNSName: tlsConfig.ServerName, Intermediates: x509.NewCertPool(), } certs := testConn.ConnectionState().PeerCertificates for i, cert := range certs { if i == 0 { continue } opts.Intermediates.AddCert(cert) } _, err = certs[0].Verify(opts) if err != nil { if _, ok := err.(x509.UnknownAuthorityError); ok { pubKey, err := libtrust.FromCryptoPublicKey(certs[0].PublicKey) if err != nil { return nil, fmt.Errorf("Error extracting public key from certificate: %s", err) } // If server is not a known host, prompt user to ask whether it should // be trusted and add to the known hosts file if promptUnknownKey(pubKey, addr) { pubKey.AddExtendedField("hosts", []string{addr}) err = libtrust.AddKeySetFile(knownHostsPath, pubKey) if err != nil { return nil, fmt.Errorf("Error saving updated host keys file: %s", err) } ca, err := libtrust.GenerateCACert(trustKey, pubKey) if err != nil { return nil, fmt.Errorf("Error generating CA: %s", err) } tlsConfig.RootCAs.AddCert(ca) } else { return nil, fmt.Errorf("Cancelling request due to invalid certificate") } } else { return nil, fmt.Errorf("TLS verification error: %s", err) } } testConn.Close() tlsConfig.InsecureSkipVerify = false return tlsConfig, nil }
func main() { // Load Client Key. clientKey, err := libtrust.LoadKeyFile(privateKeyFilename) if err != nil { log.Fatal(err) } // Generate Client Certificate. selfSignedClientCert, err := libtrust.GenerateSelfSignedClientCert(clientKey) if err != nil { log.Fatal(err) } // Load trusted host keys. hostKeys, err := libtrust.LoadKeySetFile(trustedHostsFilename) if err != nil { log.Fatal(err) } // Ensure the host we want to connect to is trusted! host, _, err := net.SplitHostPort(serverAddress) if err != nil { log.Fatal(err) } serverKeys, err := libtrust.FilterByHosts(hostKeys, host, false) if err != nil { log.Fatalf("%q is not a known and trusted host", host) } // Generate a CA pool with the trusted host's key. caPool, err := libtrust.GenerateCACertPool(clientKey, serverKeys) if err != nil { log.Fatal(err) } // Create HTTP Client. client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ Certificates: []tls.Certificate{ tls.Certificate{ Certificate: [][]byte{selfSignedClientCert.Raw}, PrivateKey: clientKey.CryptoPrivateKey(), Leaf: selfSignedClientCert, }, }, RootCAs: caPool, }, }, } var makeRequest = func(url string) { resp, err := client.Get(url) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } log.Println(resp.Status) log.Println(string(body)) } // Make the request to the trusted server! makeRequest(fmt.Sprintf("https://%s", serverAddress)) }