fixes http://pad.lv/1604474 - userdata execution fails on Windows #226

Merged
merged 1 commit into from Jul 28, 2016
Jump to file or symbol
Failed to load files and symbols.
+142 −31
Split
@@ -1,8 +1,6 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
-// +build go1.3
-
package utils
import (
@@ -41,11 +39,18 @@ func NewHttpTLSTransport(tlsConfig *tls.Config) *http.Transport {
// Unfortunately we can't drop the RSA algorithms because our servers aren't
// generating ECDHE keys.
var knownGoodCipherSuites = []uint16{
+ // These are technically useless for Juju, since we use an RSA certificate,
+ // but they also don't hurt anything, and supporting an ECDSA certificate
+ // could be useful in the future.
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+
+ // Windows doesn't support GCM currently, so we need these for RSA support.
+ tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
}
// SecureTLSConfig returns a tls.Config that conforms to Juju's security
View
@@ -0,0 +1,135 @@
+// Copyright 2016 Canonical Ltd.
+// Licensed under the LGPLv3, see LICENCE file for details.
+
+package utils
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+
+ jc "github.com/juju/testing/checkers"
+ gc "gopkg.in/check.v1"
+)
+
+type TLSSuite struct{}
+
+var _ = gc.Suite(TLSSuite{})
+
+func (TLSSuite) TestWinCipher(c *gc.C) {
+ if runtime.GOOS != "windows" {
+ c.Skip("Windows-specific test.")
+ }
+
+ d := c.MkDir()
+ go runServer(d, c)
+
+ out := filepath.Join(d, "out.txt")
+
+ // this script enables TLS 1.2, accepts whatever cert the server has (since
+ // it's self-signed), then tries to connect to the web server.
+ script := fmt.Sprintf(`[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
+(New-Object System.Net.WebClient).DownloadFile("https://127.0.0.1:10443", "%s")
+`, out)
+ err := runPS(d, script)
+ c.Assert(err, jc.ErrorIsNil)
+ b, err := ioutil.ReadFile(out)
+ c.Assert(err, jc.ErrorIsNil)
+ c.Assert(string(b), gc.Equals, "This is an example server.\n")
+}
+
+func runServer(dir string, c *gc.C) {
+ handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ w.Header().Set("Content-Type", "text/plain")
+ w.Write([]byte("This is an example server.\n"))
+ })
+
+ s := http.Server{
+ Addr: ":10443",
+ TLSConfig: SecureTLSConfig(),
+ Handler: handler,
+ }
+
+ certFile := filepath.Join(dir, "cert.pem")
+ err := ioutil.WriteFile(certFile, []byte(cert), 0600)
+ c.Assert(err, jc.ErrorIsNil)
+ keyFile := filepath.Join(dir, "key.pem")
+ err = ioutil.WriteFile(keyFile, []byte(key), 0600)
+ c.Assert(err, jc.ErrorIsNil)
+
+ err = s.ListenAndServeTLS(certFile, keyFile)
+ c.Assert(err, jc.ErrorIsNil)
+}
+
+func runPS(dir, script string) error {
+ scriptFile := filepath.Join(dir, "script.ps1")
+ args := []string{
+ "-NoProfile",
+ "-NonInteractive",
+ "-ExecutionPolicy", "RemoteSigned",
+ "-File", scriptFile,
+ }
+ // Exceptions don't result in a non-zero exit code by default
+ // when using -File. The exit code of an explicit "exit" when
+ // using -Command is ignored and results in an exit code of 1.
+ // We use -File and trap exceptions to cover both.
+ script = "trap {Write-Error $_; exit 1}\n" + script
+ if err := ioutil.WriteFile(scriptFile, []byte(script), 0600); err != nil {
+ return err
+ }
+ cmd := exec.Command("powershell.exe", args...)
+ return cmd.Run()
+}
+
+const (
+ cert = `-----BEGIN CERTIFICATE-----
+MIIC9TCCAd2gAwIBAgIRALhL8rNhi3x29T8g/AwK9bAwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA3MjYxNjI4MzRaFw0xNzA3MjYxNjI4
+MzRaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCaVIZUmQdBTXYATbTmMhscCTUSNt+Dn3OP8w2v/2QJyUz3s1eiiuec
+ymD+6TC7lNjzIXhFJnHTyuo/p2d2lHNvbQmUh0kMjPxnIDaCqWZXcjR+vnFo4jgl
+VtxCqPG2zi62kZxB0Pu9DzJ7AlqF9BTbpu0INDyFzLJtj73RIv00kRDTpFzHQSNN
+tzi9ZzKY7ZS6urftqXc4pqoaSyFXqw7uSNcBcr7Cc8oXIz5tQoVU5m0uKBGOQvwC
+b+ICd+RIYS09L1E76UGpDcrJ0LQlysQ/ZMmSsA5YHGf5KE+N0WnWdQCADq3voQra
+q47HBpH+ByA1F1REMwgMoFNZRNrEHdXFAgMBAAGjRjBEMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMA8GA1UdEQQIMAaH
+BH8AAAEwDQYJKoZIhvcNAQELBQADggEBAJPwxR3fhEpZz2JB2dAUuj0KqFD7uPQp
+m30Slu3cihqQkoaGiSMQdGSZ/VnieHbS/XaZo8JqixU8RucYjVT2eM5YRgcGxU91
+L4yJfPm7qPwGIvwpfqlZK5GcpC/qk3joNqL43gGfn6vbtqw+wF33yfcyTlTO1hwN
+vZSU4HC3Hz+FoFnmqkW5lXiuggm/jsdWqPIDA0NJHrws/wjqu3T+wQcfTvIwIPMG
+WFmUP5hvWD/9HpizJqROhRZwfsJHDpHDu0nKgSDnV1gX2S5XaUsUWu53V/Hczbo0
+fSD4wg+Zd/x3fh+EpOd1qbHmXrDWSs4z/T61yKzrgENd/kSncJC38pg=
+-----END CERTIFICATE-----
+`
+ key = `-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAmlSGVJkHQU12AE205jIbHAk1Ejbfg59zj/MNr/9kCclM97NX
+oornnMpg/ukwu5TY8yF4RSZx08rqP6dndpRzb20JlIdJDIz8ZyA2gqlmV3I0fr5x
+aOI4JVbcQqjxts4utpGcQdD7vQ8yewJahfQU26btCDQ8hcyybY+90SL9NJEQ06Rc
+x0EjTbc4vWcymO2Uurq37al3OKaqGkshV6sO7kjXAXK+wnPKFyM+bUKFVOZtLigR
+jkL8Am/iAnfkSGEtPS9RO+lBqQ3KydC0JcrEP2TJkrAOWBxn+ShPjdFp1nUAgA6t
+76EK2quOxwaR/gcgNRdURDMIDKBTWUTaxB3VxQIDAQABAoIBAQCBktX10UW2HkMk
+nhlz7D22nERito+TAx0Tjw2+5r4nOUvV7E13uwgbLA+j9kVkOOStvTwtUsne+E8U
+gojrllgVBYc1nSBH2VdRfkpGCdRTNx+8CklNtiFNuE/V5+KJiTLPNhHrcHrrkQbh
+IGjAbt3UTaJVcQYfkG1+b2D/ZlERAC0s0lnqidoqeAaiXDmDesIz+gXkpfbt5mHa
+f/LRFRvjtBDjCOTkZ3OdFeSyW+z4zs75vvk3amQNixGW74obFUZFBvF81yUZH7kf
+bWBMJMIo024oo4Rpi5k279gx2pWNLHQ68AWF/zLbu32xGrSQuTelVU5MNgEDVB9W
+3T01iHwBAoGBAMGGslxNYcf2lg0pW6II4EmOSvbdZ5z9kmV92wkN4zTP3Tzr/Kzf
+UMALczvCBYplo6Q6nR+TvRukl8Mr1e5m7Ophfv21vZfprs2YXigL9vTZKRsis8Fk
+QSK2kO9CVnWjFu11jYCDN9nUD+9lB+ry9grdY0744a8dTsxmZ1m1ZwA1AoGBAMwm
+nF0+OnMkILfsnaK6PVsJBUI5N/j05P/mDQcDZdQMVOBSh/kceQ4LWHXdL0lMVLBY
+pGPXqwsO8Q/d2R2oI1acgIFcl73FTchrQd1YaHmnyfqInhKt9QOXj1c0ii4BL3ff
+iGVf4gqQVH0B2nK7pjkBlwvpjsYFVDHP9/xkXlFRAoGAC9mgoFBItYLe601mBAUB
+Ht/srTMffhh012wedm54RCqaRHm6zicafbf1xWn7Bt90ZsEEEAPu53tro5LSlbeN
+uEhiC00On/e6MXKsCU26QIHvp263jRcDegmt1Ei+nJNw+vdgw8bFK7x1gVYxZuyb
+rkyiIRrSTvO/eHqox3B5LyUCgYAmKZWTTJ2qhndjSmURVVVA3kfQYFfZPxZLy9pl
+lDoF0KRRJrxqUetDN9W6erVrM0ylhnx8eYVs1Mc1WxhKFfM9LpZLGF75R5fJvlsa
+oHsvOrFkFwPNpB0oJb3S5GxsOyZ/dxbNNIZRyTcyAxWt2uwwvd5ZiLh6xeY+RY0q
+7iw/cQKBgQCaWJ8bSNNhQeaBSW5IVHFctYtLPv9aPHagBdJkKmeb06HWQHi+AvkY
+nd0dgM/TfgtnuhbVS4ISkT4vZoSn84hOE7BG5rSPE+/q24Wv5gG0PI1sky8tmXzX
+juAEWSJVCSE0TK/mvBVdlyKOJoEgtfMcRfDQfA1rI9My0rU+/Y5A0w==
+-----END RSA PRIVATE KEY-----`
+)
View
@@ -1,29 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-// +build !go1.3
-
-package utils
-
-import (
- "crypto/tls"
- "net/http"
-)
-
-// NewHttpTLSTransport returns a new http.Transport constructed with the TLS config
-// and the necessary parameters for Juju.
-func NewHttpTLSTransport(tlsConfig *tls.Config) *http.Transport {
- // See https://code.google.com/p/go/issues/detail?id=4677
- // We need to force the connection to close each time so that we don't
- // hit the above Go bug.
- transport := &http.Transport{
- Proxy: http.ProxyFromEnvironment,
- TLSClientConfig: tlsConfig,
- DisableKeepAlives: true,
- Dial: dial,
- // Go 1.2 does not support the TLSHandshaketimeout
- // TLSHandshakeTimeout: 10 * time.Second,
- }
- registerFileProtocol(transport)
- return transport
-}