diff --git a/internal/certs/certs.go b/internal/certs/certs.go index b5c81d807c..872a0d5f77 100644 --- a/internal/certs/certs.go +++ b/internal/certs/certs.go @@ -110,7 +110,7 @@ func SelfSignedOrLetsEncryptCert(manager *autocert.Manager, serverName string) f } logging.L.Info("new server certificate", - zap.String("SHA256 fingerprint", Fingerprint(PEMDecode(certBytes)))) + zap.String("SHA256 fingerprint", Fingerprint(pemDecode(certBytes)))) } keypair, err := tls.X509KeyPair(certBytes, keyBytes) @@ -131,7 +131,7 @@ func Fingerprint(raw []byte) string { return strings.ToUpper(s) } -func PEMDecode(raw []byte) []byte { +func pemDecode(raw []byte) []byte { block, _ := pem.Decode(raw) return block.Bytes } diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 850f3f8116..bddc71354c 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -20,7 +20,6 @@ import ( "github.com/infrahq/infra/api" "github.com/infrahq/infra/internal" - "github.com/infrahq/infra/internal/certs" "github.com/infrahq/infra/internal/cmd/cliopts" "github.com/infrahq/infra/internal/connector" "github.com/infrahq/infra/internal/logging" @@ -102,12 +101,10 @@ func httpTransportForHostConfig(config *ClientHostConfig) *http.Transport { pool = x509.NewCertPool() } - if len(config.TrustedCertificate) > 0 { - cert, err := x509.ParseCertificate(certs.PEMDecode(config.TrustedCertificate)) - if err != nil { + if config.TrustedCertificate != "" { + ok := pool.AppendCertsFromPEM([]byte(config.TrustedCertificate)) + if !ok { logging.S.Warnf("Failed to read trusted certificates for server: %v", err) - } else { - pool.AddCert(cert) } } diff --git a/internal/cmd/config.go b/internal/cmd/config.go index df70ce3d88..d1b9678412 100644 --- a/internal/cmd/config.go +++ b/internal/cmd/config.go @@ -32,7 +32,7 @@ type ClientHostConfig struct { Current bool `json:"current"` // TrustedCertificate is the PEM encoded TLS certificate used by the server // that was verified and trusted by the user as part of login. - TrustedCertificate []byte `json:"trusted-certificate"` + TrustedCertificate string `json:"trusted-certificate"` } // checks if user is logged in to the given session (ClientHostConfig) diff --git a/internal/cmd/login.go b/internal/cmd/login.go index 58e9c51ad1..8a298e9d36 100644 --- a/internal/cmd/login.go +++ b/internal/cmd/login.go @@ -35,7 +35,7 @@ type loginCmdOptions struct { Provider string SkipTLSVerify bool // TODO: add flag for trusted certificate - TrustedCertificate []byte + TrustedCertificate string NonInteractive bool } @@ -255,7 +255,7 @@ func updateInfraConfig(lc loginClient, loginReq *api.LoginRequest, loginRes *api } clientHostConfig.SkipTLSVerify = t.TLSClientConfig.InsecureSkipVerify if len(lc.TrustedCertificate) > 0 { - clientHostConfig.TrustedCertificate = certs.PEMEncodeCertificate(lc.TrustedCertificate) + clientHostConfig.TrustedCertificate = lc.TrustedCertificate } if loginReq.OIDC != nil { @@ -388,8 +388,10 @@ func runSignupForLogin(cli *CLI, client *api.Client) (*api.LoginRequestPasswordC } type loginClient struct { - APIClient *api.Client - TrustedCertificate []byte + APIClient *api.Client + // TrustedCertificate is a PEM encoded certificate that has been trusted by + // the user for TLS communication with the server. + TrustedCertificate string } // Only used when logging in or switching to a new session, since user has no credentials. Otherwise, use defaultAPIClient(). @@ -440,7 +442,7 @@ func newLoginClient(cli *CLI, options loginCmdOptions) (loginClient, error) { }, } c.APIClient = apiClient(options.Server, "", transport) - c.TrustedCertificate = uaErr.Cert.Raw + c.TrustedCertificate = string(certs.PEMEncodeCertificate(uaErr.Cert.Raw)) } return c, nil } @@ -593,22 +595,28 @@ to manually verify the certificate can be trusted. confirmPrompt := &survey.Select{ Message: "Options:", Options: []string{ - "I do not trust this certificate", - "Trust and save the certificate", + "NO", + "TRUST", + }, + Description: func(value string, index int) string { + switch value { + case "NO": + return "I do not trust this certificate" + case "TRUST": + return "Trust and save the certificate" + default: + return "" + } }, } var selection string if err := survey.AskOne(confirmPrompt, &selection, cli.surveyIO); err != nil { return err } - switch { - case selection == confirmPrompt.Options[0]: - return terminal.InterruptErr - case selection == confirmPrompt.Options[1]: + if selection == "TRUST" { return nil } - // TODO: can this happen? - panic("unexpected") + return terminal.InterruptErr } // Returns the host address of the Infra server that user would like to log into