Skip to content

Commit

Permalink
[SA-22192] Validate user input when user provides a pem file
Browse files Browse the repository at this point in the history
make sure user input is acctually a PEM file, see Youtrack ticket for more info.
  • Loading branch information
dlnilsson committed Jul 18, 2023
1 parent 3286eeb commit 8c6685c
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 3 deletions.
80 changes: 77 additions & 3 deletions cmd/configure/configure.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package configure

import (
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io"
"os"
"strings"

"github.com/AlecAivazis/survey/v2"
"github.com/appgate/sdpctl/pkg/configuration"
Expand All @@ -12,7 +18,6 @@ import (
"github.com/appgate/sdpctl/pkg/filesystem"
"github.com/appgate/sdpctl/pkg/network"
"github.com/appgate/sdpctl/pkg/prompt"
"github.com/appgate/sdpctl/pkg/util"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -81,15 +86,84 @@ func NewCmdConfigure(f *factory.Factory) *cobra.Command {
return cmd
}

func readPemFile(path string) (*x509.Certificate, error) {
info, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("Path %s does not exist", path)
}
return nil, fmt.Errorf("%s - %s", path, err)
}
if info.IsDir() {
return nil, fmt.Errorf("path %s is a directory, not a file", path)
}
pemData, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("not a file %s %s", path, err)
}
block, _ := pem.Decode(pemData)
if block == nil {
return nil, fmt.Errorf("expected a pem file, could not decode %s", path)
}

// See if we can parse the certificate
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}
return cert, nil
}

func certificateDetails(cert *x509.Certificate) string {
var sb strings.Builder

if len(cert.Subject.CommonName) > 0 {
sb.WriteString(fmt.Sprintf("[Subject]\n\t%s\n", cert.Subject.CommonName))
}
if len(cert.Issuer.CommonName) > 0 {
sb.WriteString(fmt.Sprintf("[Issuer]\n\t%s\n", cert.Issuer.CommonName))
}
if cert.SerialNumber != nil {
sb.WriteString(fmt.Sprintf("[Serial Number]\n\t%s\n", cert.SerialNumber))
}

sb.WriteString(fmt.Sprintf("[Not Before]\n\t%s\n", cert.NotBefore))
sb.WriteString(fmt.Sprintf("[Not After]\n\t%s\n", cert.NotAfter))

var sha1buf strings.Builder
for i, f := range sha1.Sum(cert.Raw) {
if i > 0 {
sha1buf.Write([]byte(":"))
}
sha1buf.Write([]byte(fmt.Sprintf("%02X", f)))
}
sb.WriteString(fmt.Sprintf("[Thumbprint SHA-1]\n\t%s\n", sha1buf.String()))

var sha256buf strings.Builder
for i, f := range sha256.Sum256(cert.Raw) {
if i > 0 {
sha256buf.Write([]byte(":"))
}
sha256buf.Write([]byte(fmt.Sprintf("%02X", f)))
}
sb.WriteString(fmt.Sprintf("[Thumbprint SHA-256]\n\t%s\n", sha256buf.String()))

return sb.String()
}

func configRun(cmd *cobra.Command, args []string, opts *configureOptions) error {
if len(opts.URL) < 1 {
return errors.New("Missing URL for the Controller")
}
if len(opts.PEM) > 0 {
opts.PEM = filesystem.AbsolutePath(opts.PEM)
if ok, err := util.FileExists(opts.PEM); err != nil || !ok {
return fmt.Errorf("File not found: %s", opts.PEM)
cert, err := readPemFile(opts.PEM)
if err != nil {
return err
}
fmt.Fprintln(opts.Out, "Added PEM as trusted source for sdpctl")
fmt.Fprintln(opts.Out, certificateDetails(cert))

viper.Set("pem_filepath", opts.PEM)
}
u, err := configuration.NormalizeConfigurationURL(opts.URL)
Expand Down
65 changes: 65 additions & 0 deletions cmd/configure/configure_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package configure

import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/json"
"io"
"os"
"path/filepath"
"strings"
"testing"
"time"

expect "github.com/Netflix/go-expect"
"github.com/appgate/sdpctl/pkg/configuration"
"github.com/appgate/sdpctl/pkg/factory"
"github.com/appgate/sdpctl/pkg/prompt"
pseudotty "github.com/creack/pty"
"github.com/google/go-cmp/cmp"
"github.com/hinshun/vt10x"
"github.com/spf13/viper"
)
Expand Down Expand Up @@ -256,3 +260,64 @@ func TestConfigCmdWithExistingAddr(t *testing.T) {
t.Fatalf("wrong addr stored in config, expected %q got %q", want, v)
}
}

var demoCert = `-----BEGIN CERTIFICATE-----
MIIB4TCCAYugAwIBAgIUblfrUTadV6hHYGW8B/T0kVve6GAwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTEyMDYxMDI2NTVaFw0zMTEy
MDQxMDI2NTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwXDANBgkqhkiG9w0BAQEF
AANLADBIAkEAyu++YjSfKQW7DfYmKQbEIG3TyD91Cce1VBVg+KwLP/iBNLQO1ZFR
gYoiQRHqOH9iHOZRfJBhZiAB7MSxDuIdrwIDAQABo1MwUTAdBgNVHQ4EFgQU/iVT
noAPQ09G4sC26jHKu0xnsXQwHwYDVR0jBBgwFoAU/iVTnoAPQ09G4sC26jHKu0xn
sXQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAANBADwEHw0k7sUuIetl
YdaOvNqyH5SnPUDncp4Gkpr61rpVQzwadnCTtiAisYor+gD1lehtj/AjZMxvJdOm
K0mfdZQ=
-----END CERTIFICATE-----`

func Test_certificateDetails(t *testing.T) {
before, _ := time.Parse("2006-01-02 15:04", "2018-01-20 04:35")
after, _ := time.Parse("2006-01-02 15:04", "2024-01-20 04:35")

tests := []struct {
name string
cert *x509.Certificate
want string
}{
{
name: "bla",
cert: &x509.Certificate{
Raw: []byte(demoCert),
NotBefore: before,
NotAfter: after,
Subject: pkix.Name{
CommonName: "controller.appgate.com",
},
Issuer: pkix.Name{
CommonName: "Appgate SDP CA",
},
},
want: `[Subject]
controller.appgate.com
[Issuer]
Appgate SDP CA
[Not Before]
2018-01-20 04:35:00 +0000 UTC
[Not After]
2024-01-20 04:35:00 +0000 UTC
[Thumbprint SHA-1]
00:2E:E6:59:93:63:70:E9:50:7B:90:70:9F:4B:58:D3:30:E5:B5:F5
[Thumbprint SHA-256]
8E:31:BA:3F:9E:06:9F:A1:86:5A:2E:14:58:84:C9:7E:23:51:93:8D:92:F3:A8:9E:EE:BC:FC:11:AD:DF:12:1C
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := certificateDetails(tt.cert)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("output mismatch (-want +got):\n%s", diff)
}
})
}
}
13 changes: 13 additions & 0 deletions cmd/configure/testdata/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB4TCCAYugAwIBAgIUblfrUTadV6hHYGW8B/T0kVve6GAwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTEyMDYxMDI2NTVaFw0zMTEy
MDQxMDI2NTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwXDANBgkqhkiG9w0BAQEF
AANLADBIAkEAyu++YjSfKQW7DfYmKQbEIG3TyD91Cce1VBVg+KwLP/iBNLQO1ZFR
gYoiQRHqOH9iHOZRfJBhZiAB7MSxDuIdrwIDAQABo1MwUTAdBgNVHQ4EFgQU/iVT
noAPQ09G4sC26jHKu0xnsXQwHwYDVR0jBBgwFoAU/iVTnoAPQ09G4sC26jHKu0xn
sXQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAANBADwEHw0k7sUuIetl
YdaOvNqyH5SnPUDncp4Gkpr61rpVQzwadnCTtiAisYor+gD1lehtj/AjZMxvJdOm
K0mfdZQ=
-----END CERTIFICATE-----

0 comments on commit 8c6685c

Please sign in to comment.