| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Minio Cloud Storage, (C) 2015, 2016 Minio, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	"bufio" | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 	"crypto/rand" | 
					
						
							|  |  |  | 	"crypto/rsa" | 
					
						
							|  |  |  | 	"crypto/tls" | 
					
						
							|  |  |  | 	"crypto/x509" | 
					
						
							|  |  |  | 	"crypto/x509/pkix" | 
					
						
							|  |  |  | 	"encoding/pem" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/http/httptest" | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestClose(t *testing.T) { | 
					
						
							|  |  |  | 	// Create ServerMux
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	m := NewServerMux("", nil) | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if err := m.Close(); err != nil { | 
					
						
							|  |  |  | 		t.Error("Server errored while trying to Close", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | func TestServerMux(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	ts := httptest.NewUnstartedServer(nil) | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	defer ts.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create ServerMux
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	m := NewServerMux("", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 		fmt.Fprint(w, "hello") | 
					
						
							|  |  |  | 	})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set the test server config to the mux
 | 
					
						
							|  |  |  | 	ts.Config = &m.Server | 
					
						
							|  |  |  | 	ts.Start() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	// Create a ListenerMux
 | 
					
						
							|  |  |  | 	lm := &ListenerMux{ | 
					
						
							|  |  |  | 		Listener: ts.Listener, | 
					
						
							|  |  |  | 		config:   &tls.Config{}, | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	m.listener = lm | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	client := http.Client{} | 
					
						
							|  |  |  | 	res, err := client.Get(ts.URL) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	got, err := ioutil.ReadAll(res.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if string(got) != "hello" { | 
					
						
							|  |  |  | 		t.Errorf("got %q, want hello", string(got)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure there is only 1 connection
 | 
					
						
							|  |  |  | 	m.mu.Lock() | 
					
						
							|  |  |  | 	if len(m.conns) < 1 { | 
					
						
							|  |  |  | 		t.Fatal("Should have 1 connections") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Close the server
 | 
					
						
							|  |  |  | 	m.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure there are zero connections
 | 
					
						
							|  |  |  | 	m.mu.Lock() | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	if len(m.conns) > 0 { | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 		t.Fatal("Should have 0 connections") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestServerCloseBlocking(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	ts := httptest.NewUnstartedServer(nil) | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	defer ts.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create ServerMux
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	m := NewServerMux("", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 		fmt.Fprint(w, "hello") | 
					
						
							|  |  |  | 	})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set the test server config to the mux
 | 
					
						
							|  |  |  | 	ts.Config = &m.Server | 
					
						
							|  |  |  | 	ts.Start() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	// Create a ListenerMux.
 | 
					
						
							|  |  |  | 	lm := &ListenerMux{ | 
					
						
							|  |  |  | 		Listener: ts.Listener, | 
					
						
							|  |  |  | 		config:   &tls.Config{}, | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	m.listener = lm | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dial := func() net.Conn { | 
					
						
							|  |  |  | 		c, cerr := net.Dial("tcp", ts.Listener.Addr().String()) | 
					
						
							|  |  |  | 		if cerr != nil { | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 			t.Fatal(cerr) | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return c | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Dial to open a StateNew but don't send anything
 | 
					
						
							|  |  |  | 	cnew := dial() | 
					
						
							|  |  |  | 	defer cnew.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Dial another connection but idle after a request to have StateIdle
 | 
					
						
							|  |  |  | 	cidle := dial() | 
					
						
							|  |  |  | 	defer cidle.Close() | 
					
						
							|  |  |  | 	cidle.Write([]byte("HEAD / HTTP/1.1\r\nHost: foo\r\n\r\n")) | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	_, err := http.ReadResponse(bufio.NewReader(cidle), nil) | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure we don't block forever.
 | 
					
						
							|  |  |  | 	m.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure there are zero connections
 | 
					
						
							|  |  |  | 	m.mu.Lock() | 
					
						
							|  |  |  | 	if len(m.conns) > 0 { | 
					
						
							|  |  |  | 		t.Fatal("Should have 0 connections") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m.mu.Unlock() | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 07:07:44 +08:00
										 |  |  | func TestListenAndServePlain(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	wait := make(chan struct{}) | 
					
						
							|  |  |  | 	addr := "127.0.0.1:" + strconv.Itoa(getFreePort()) | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	errc := make(chan error) | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 	once := &sync.Once{} | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Create ServerMux and when we receive a request we stop waiting
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	m := NewServerMux(addr, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 		fmt.Fprint(w, "hello") | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 		once.Do(func() { close(wait) }) | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ListenAndServe in a goroutine, but we don't know when it's ready
 | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	go func() { errc <- m.ListenAndServe() }() | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure we don't block by closing wait after a timeout
 | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 	tf := time.AfterFunc(time.Millisecond*500, func() { errc <- errors.New("Unable to connect to server") }) | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 07:07:44 +08:00
										 |  |  | 	wg := &sync.WaitGroup{} | 
					
						
							|  |  |  | 	wg.Add(1) | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	// Keep trying the server until it's accepting connections
 | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 	go func() { | 
					
						
							|  |  |  | 		client := http.Client{Timeout: time.Millisecond * 10} | 
					
						
							|  |  |  | 		ok := false | 
					
						
							|  |  |  | 		for !ok { | 
					
						
							|  |  |  | 			res, _ := client.Get("http://" + addr) | 
					
						
							|  |  |  | 			if res != nil && res.StatusCode == http.StatusOK { | 
					
						
							|  |  |  | 				ok = true | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 07:07:44 +08:00
										 |  |  | 		wg.Done() | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 		tf.Stop() // Cancel the timeout since we made a successful request
 | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 07:07:44 +08:00
										 |  |  | 	wg.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	// Block until we get an error or wait closed
 | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	select { | 
					
						
							|  |  |  | 	case err := <-errc: | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-19 10:45:03 +08:00
										 |  |  | 	case <-wait: | 
					
						
							|  |  |  | 		m.Close() // Shutdown the ServerMux
 | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestListenAndServeTLS(t *testing.T) { | 
					
						
							|  |  |  | 	wait := make(chan struct{}) | 
					
						
							|  |  |  | 	addr := "127.0.0.1:" + strconv.Itoa(getFreePort()) | 
					
						
							|  |  |  | 	errc := make(chan error) | 
					
						
							|  |  |  | 	once := &sync.Once{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create ServerMux and when we receive a request we stop waiting
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | 	m := NewServerMux(addr, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 		fmt.Fprint(w, "hello") | 
					
						
							|  |  |  | 		once.Do(func() { close(wait) }) | 
					
						
							|  |  |  | 	})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a cert
 | 
					
						
							|  |  |  | 	err := createCertsPath() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	certFile := mustGetCertFile() | 
					
						
							|  |  |  | 	keyFile := mustGetKeyFile() | 
					
						
							|  |  |  | 	defer os.RemoveAll(certFile) | 
					
						
							|  |  |  | 	defer os.RemoveAll(keyFile) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = generateTestCert(addr) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Error(err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ListenAndServe in a goroutine, but we don't know when it's ready
 | 
					
						
							|  |  |  | 	go func() { errc <- m.ListenAndServeTLS(certFile, keyFile) }() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure we don't block by closing wait after a timeout
 | 
					
						
							|  |  |  | 	tf := time.AfterFunc(time.Millisecond*500, func() { errc <- errors.New("Unable to connect to server") }) | 
					
						
							| 
									
										
										
										
											2016-09-01 07:07:44 +08:00
										 |  |  | 	wg := &sync.WaitGroup{} | 
					
						
							|  |  |  | 	wg.Add(1) | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Keep trying the server until it's accepting connections
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		tr := &http.Transport{ | 
					
						
							|  |  |  | 			TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		client := http.Client{ | 
					
						
							|  |  |  | 			Timeout:   time.Millisecond * 10, | 
					
						
							|  |  |  | 			Transport: tr, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ok := false | 
					
						
							|  |  |  | 		for !ok { | 
					
						
							|  |  |  | 			res, _ := client.Get("https://" + addr) | 
					
						
							|  |  |  | 			if res != nil && res.StatusCode == http.StatusOK { | 
					
						
							|  |  |  | 				ok = true | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 07:07:44 +08:00
										 |  |  | 		wg.Done() | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 		tf.Stop() // Cancel the timeout since we made a successful request
 | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 07:07:44 +08:00
										 |  |  | 	wg.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 16:29:50 +08:00
										 |  |  | 	// Block until we get an error or wait closed
 | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case err := <-errc: | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Error(err) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case <-wait: | 
					
						
							|  |  |  | 		m.Close() // Shutdown the ServerMux
 | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // generateTestCert creates a cert and a key used for testing only
 | 
					
						
							|  |  |  | func generateTestCert(host string) error { | 
					
						
							|  |  |  | 	certPath := mustGetCertFile() | 
					
						
							|  |  |  | 	keyPath := mustGetKeyFile() | 
					
						
							|  |  |  | 	priv, err := rsa.GenerateKey(rand.Reader, 2048) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) | 
					
						
							|  |  |  | 	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	template := x509.Certificate{ | 
					
						
							|  |  |  | 		SerialNumber: serialNumber, | 
					
						
							|  |  |  | 		Subject: pkix.Name{ | 
					
						
							|  |  |  | 			Organization: []string{"Minio Test Cert"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		NotBefore: time.Now(), | 
					
						
							|  |  |  | 		NotAfter:  time.Now().Add(time.Minute * 1), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, | 
					
						
							|  |  |  | 		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | 
					
						
							|  |  |  | 		BasicConstraintsValid: true, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ip := net.ParseIP(host); ip != nil { | 
					
						
							|  |  |  | 		template.IPAddresses = append(template.IPAddresses, ip) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	template.IsCA = true | 
					
						
							|  |  |  | 	template.KeyUsage |= x509.KeyUsageCertSign | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	certOut, err := os.Create(certPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) | 
					
						
							|  |  |  | 	certOut.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) | 
					
						
							|  |  |  | 	keyOut.Close() | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |