Skip to content

Commit

Permalink
[eclipse-kanto#10] Add flags to configure secure connection client ce…
Browse files Browse the repository at this point in the history
…rtificate

- removed key flag
- cert flag renamed to serverCert
- removed license files

Signed-off-by: Georgi Boyvalenkov <Georgi.Boyvalenkov@bosch.io>
  • Loading branch information
gboyvalenkov-bosch committed Aug 15, 2022
1 parent 5c2c9ad commit 89b70f2
Show file tree
Hide file tree
Showing 20 changed files with 44 additions and 344 deletions.
9 changes: 3 additions & 6 deletions internal/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ type ScriptBasedSoftwareUpdatableConfig struct {
FeatureID string
ModuleType string
ArtifactType string
Cert string
Key string
ServerCert string
InstallCommand command
}

Expand All @@ -59,8 +58,7 @@ type ScriptBasedSoftwareUpdatable struct {
dittoClient *ditto.Client
mqttClient MQTT.Client
artifactType string
cert string
key string
serverCert string
installCommand *command
}

Expand All @@ -79,8 +77,7 @@ func NewScriptBasedSU(scriptSUPConfig *ScriptBasedSoftwareUpdatableConfig) (*Scr
store: localStorage,
// Build install script command
installCommand: &scriptSUPConfig.InstallCommand,
cert: scriptSUPConfig.Cert,
key: scriptSUPConfig.Key,
serverCert: scriptSUPConfig.ServerCert,
// Define the module artifact(s) type: archive or plane
artifactType: scriptSUPConfig.ArtifactType,
// Create queue with size 10
Expand Down
2 changes: 1 addition & 1 deletion internal/feature_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Started:
Downloading:
if opError = f.store.DownloadModule(toDir, module, func(percent int) {
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading).WithProgress(percent))
}, f.cert, f.key); opError != nil {
}, f.serverCert); opError != nil {
opErrorMsg = errDownload
return opError == storage.ErrCancel
}
Expand Down
2 changes: 1 addition & 1 deletion internal/feature_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Started:
Downloading:
if opError = f.store.DownloadModule(dir, module, func(progress int) {
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading).WithProgress(progress))
}, f.cert, f.key); opError != nil {
}, f.serverCert); opError != nil {
opErrorMsg = errDownload
return opError == storage.ErrCancel
}
Expand Down
3 changes: 1 addition & 2 deletions internal/feature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ func TestScriptBasedCore(t *testing.T) {

testDownloadInstall(feature, mc, w.getSoftwareArtifacts(false, "install"), t)

feature.cert = testCert
feature.key = testKey
feature.serverCert = testCert
testDownloadInstall(feature, mc, wSecure.getSoftwareArtifacts(true, "install"), t)
}

Expand Down
10 changes: 4 additions & 6 deletions internal/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ const (
flagModuleType = "moduleType"
flagArtifactType = "artifactType"
flagInstall = "install"
flagCert = "serverCert"
flagLogFile = "logFile"
flagLogLevel = "logLevel"
flagLogFileSize = "logFileSize"
flagLogFileCount = "logFileCount"
flagLogFileMaxAge = "logFileMaxAge"
flagCert = "cert"
flagKey = "key"
)

var (
Expand All @@ -60,8 +59,7 @@ type cfg struct {
ModuleType string `json:"moduleType" def:"software" descr:"Module type of SoftwareUpdatable"`
ArtifactType string `json:"artifactType" def:"archive" descr:"Defines the module artifact type: archive or plane"`
Install []string `json:"install" descr:"Defines the absolute path to install script"`
Cert string `json:"cert" descr:"A PEM encoded certificate \"file\" for secure artifact download"`
Key string `json:"key" descr:"A PEM encoded unencrypted private key for secure artifact download"`
ServerCert string `json:"serverCert" descr:"A PEM encoded certificate \"file\" for secure artifact download"`
LogFile string `json:"logFile" def:"logs/log.txt" descr:"Log file location in storage directory"`
LogLevel string `json:"logLevel" def:"INFO" descr:"Log levels are ERROR, WARNING, INFO, DEBUG, TRACE"`
LogFileSize int `json:"logFileSize" def:"2" descr:"Log file size in MB before it gets rotated"`
Expand Down Expand Up @@ -111,7 +109,7 @@ func initFlagsWithDefaultValues(config interface{}) {
case int:
value, err := strconv.Atoi(defaultValue)
if err != nil {
log.Println(fmt.Sprintf("Error parsing integer argument %v with value %v", fieldType.Name, defaultValue))
log.Printf("error parsing integer argument %v with value %v", fieldType.Name, defaultValue)
}
flag.IntVar(pointer.(*int), flagName, value, description)
}
Expand All @@ -133,7 +131,7 @@ func loadDefaultValues() *cfg {
case int:
value, err := strconv.Atoi(defaultValue)
if err != nil {
log.Println(fmt.Sprintf("Error parsing integer argument %v with value %v", fieldType.Name, defaultValue))
log.Printf("error parsing integer argument %v with value %v", fieldType.Name, defaultValue)
}
fieldValue.Set(reflect.ValueOf(value))
}
Expand Down
9 changes: 3 additions & 6 deletions internal/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ func TestFlagsHasHigherPriority(t *testing.T) {
expectedArtifact := "TestArchive"
expectedFeatureID := "TestFeature"
expectedInstall := "TestInstall"
expectedCert := "TestCert"
expectedKey := "TestKey"
expectedServerCert := "TestCert"
expectedLogFile := ""
expectedLogFileCount := 4
expectedLogFileMaxAge := 13
Expand All @@ -129,8 +128,7 @@ func TestFlagsHasHigherPriority(t *testing.T) {
c(flagArtifactType, expectedArtifact),
c(flagFeatureID, expectedFeatureID),
c(flagInstall, expectedInstall),
c(flagCert, expectedCert),
c(flagKey, expectedKey),
c(flagCert, expectedServerCert),
c(flagLogFile, expectedLogFile),
c(flagLogFileCount, strconv.Itoa(expectedLogFileCount)),
c(flagLogFileMaxAge, strconv.Itoa(expectedLogFileMaxAge)),
Expand All @@ -152,8 +150,7 @@ func TestFlagsHasHigherPriority(t *testing.T) {
Broker: expectedFlagBroker,
Username: expectedUsername,
Password: expectedPassword,
Cert: expectedCert,
Key: expectedKey,
ServerCert: expectedServerCert,
StorageLocation: expectedStorageLocation,
FeatureID: expectedFeatureID,
ModuleType: expectedModuleType,
Expand Down
28 changes: 9 additions & 19 deletions internal/storage/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (
const prefix = "_temporary-"

// downloadArtifact tries to resume previous download operation or perform a new download.
func downloadArtifact(to string, artifact *Artifact, progress progressBytes, cert, key string, done chan struct{}) error {
func downloadArtifact(to string, artifact *Artifact, progress progressBytes, serverCert string, done chan struct{}) error {
logger.Infof("Download [%s] to file [%s]", artifact.Link, to)

// Check for available file.
Expand Down Expand Up @@ -74,12 +74,12 @@ func downloadArtifact(to string, artifact *Artifact, progress progressBytes, cer

if stat, err := os.Stat(tmp); !os.IsNotExist(err) {
// Try to resume previous download.
if dError = resume(tmp, stat.Size(), artifact, progress, cert, key, done); dError != nil {
if dError = resume(tmp, stat.Size(), artifact, progress, serverCert, done); dError != nil {
return dError
}
} else {
// No available previous download, perform a full download.
response, err := getDownloadResponse(artifact.Link, 0, cert, key)
response, err := requestDownload(artifact.Link, 0, serverCert)
if err != nil {
return err
}
Expand All @@ -99,9 +99,9 @@ func downloadArtifact(to string, artifact *Artifact, progress progressBytes, cer
return os.Rename(tmp, to)
}

func resume(to string, offset int64, artifact *Artifact, progress progressBytes, cert, key string, done chan struct{}) error {
func resume(to string, offset int64, artifact *Artifact, progress progressBytes, serverCert string, done chan struct{}) error {
// Send the HTTP request and get its response.
response, err := getDownloadResponse(artifact.Link, offset, cert, key)
response, err := requestDownload(artifact.Link, offset, serverCert)
if err != nil {
return err
}
Expand Down Expand Up @@ -139,7 +139,7 @@ func resume(to string, offset int64, artifact *Artifact, progress progressBytes,
return validate(to, artifact.HashType, artifact.HashValue)
}

func getDownloadResponse(link string, offset int64, certFile, keyFile string) (*http.Response, error) {
func requestDownload(link string, offset int64, serverCert string) (*http.Response, error) {
// Create new HTTP request with Range header.
request, err := http.NewRequest(http.MethodGet, link, nil)
if err != nil {
Expand All @@ -151,20 +151,11 @@ func getDownloadResponse(link string, offset int64, certFile, keyFile string) (*
}

var transport http.Transport
var cert tls.Certificate
var caCertPool *x509.CertPool
var certificates []tls.Certificate
if len(certFile) > 0 {
cert, err = tls.LoadX509KeyPair(certFile, keyFile)
if len(serverCert) > 0 {
caCert, err := ioutil.ReadFile(serverCert)
if err != nil {
logger.Errorf("Error loading certificate key pair file(s) - \"%s\", \"%s\"",
certFile, keyFile)
return nil, err
}
certificates = []tls.Certificate{cert}
caCert, err := ioutil.ReadFile(certFile)
if err != nil {
logger.Errorf("Error reading CA certificate file - \"%s\"", certFile)
logger.Errorf("Error reading CA certificate file - \"%s\"", serverCert)
return nil, err
}
caCertPool = x509.NewCertPool()
Expand All @@ -176,7 +167,6 @@ func getDownloadResponse(link string, offset int64, certFile, keyFile string) (*
config := &tls.Config{ // using the system CA pool
InsecureSkipVerify: false,
RootCAs: caCertPool,
Certificates: certificates,
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
CipherSuites: supportedCipherSuites(),
Expand Down
32 changes: 16 additions & 16 deletions internal/storage/download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func testDownloadToFile(arts []*Artifact, certFile, certKey string, t *testing.T

// 1. Resume downlaod of corrupted temporary file.
WriteLn(filepath.Join(dir, prefix+art.FileName), "wrong start")
if err := downloadArtifact(name, art, nil, certFile, certKey, make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, certFile, make(chan struct{})); err == nil {
t.Fatal("downlaod of corrupted temporary file must fail")
}

Expand All @@ -147,7 +147,7 @@ func testDownloadToFile(arts []*Artifact, certFile, certKey string, t *testing.T
callback := func(bytes int64) {
close(done)
}
if err := downloadArtifact(name, art, callback, certFile, certKey, done); err != ErrCancel {
if err := downloadArtifact(name, art, callback, certFile, done); err != ErrCancel {
t.Fatalf("failed to cancel download operation: %v", err)
}
if _, err := os.Stat(filepath.Join(dir, prefix+art.FileName)); os.IsNotExist(err) {
Expand All @@ -156,13 +156,13 @@ func testDownloadToFile(arts []*Artifact, certFile, certKey string, t *testing.T

// 3. Resume previous download operation.
callback = func(bytes int64) { /* Do nothing. */ }
if err := downloadArtifact(name, art, callback, certFile, certKey, make(chan struct{})); err != nil {
if err := downloadArtifact(name, art, callback, certFile, make(chan struct{})); err != nil {
t.Fatalf("failed to download artifact: %v", err)
}
check(name, art.Size, t)

// 4. Download available file.
if err := downloadArtifact(name, art, callback, certFile, certKey, make(chan struct{})); err != nil {
if err := downloadArtifact(name, art, callback, certFile, make(chan struct{})); err != nil {
t.Fatalf("failed to download artifact: %v", err)
}
check(name, art.Size, t)
Expand All @@ -175,14 +175,14 @@ func testDownloadToFile(arts []*Artifact, certFile, certKey string, t *testing.T
// 5. Try to resume with file bigger than expected.
WriteLn(filepath.Join(dir, prefix+art.FileName), "1111111111111")
art.Size -= 10
if err := downloadArtifact(name, art, nil, certFile, certKey, make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, certFile, make(chan struct{})); err == nil {
t.Fatal("validate resume with file bigger than expected")
}

// 6. Try to resume from missing link.
WriteLn(filepath.Join(dir, prefix+art.FileName), "1111111111111")
art.Link = "http://localhost:43234/test-missing.txt"
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err == nil {
t.Fatal("failed to validate with missing link")
}

Expand Down Expand Up @@ -214,41 +214,41 @@ func TestDownloadToFileError(t *testing.T) {

// 1. Resume is not supported.
WriteLn(filepath.Join(dir, prefix+art.FileName), "1111")
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err != nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err != nil {
t.Fatalf("failed to download file artifact: %v", err)
}
check(name, art.Size, t)

// 2. Try with missing checksum.
art.HashValue = ""
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err == nil {
t.Fatal("validatted with missing checksum")
}

// 3. Try with missing link.
art.Link = "http://localhost:43234/test-missing.txt"
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err == nil {
t.Fatal("failed to validate with missing link")
}

// 4. Try with wrong checksum type.
art.Link = "http://localhost:43234/test-simple.txt"
art.HashType = ""
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err == nil {
t.Fatal("validate with wrong checksum type")
}

// 5. Try with wrong checksum format.
art.HashValue = ";;"
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err == nil {
t.Fatal("validate with wrong checksum format")
}

// 6. Try to download file bigger than expected.
art.HashType = "MD5"
art.HashValue = "ab2ce340d36bbaafe17965a3a2c6ed5b"
art.Size -= 10
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err == nil {
t.Fatal("validate with file bigger than expected")
}

Expand Down Expand Up @@ -281,22 +281,22 @@ func TestDownloadToFileSecureError(t *testing.T) {
name := filepath.Join(dir, art.FileName)

// 1. Try download with expired certificate
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err == nil {
t.Fatalf("validated with expired certificate: %v", err)
}
if err := downloadArtifact(name, art, nil, expiredCert, expiredKey, make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, expiredCert, make(chan struct{})); err == nil {
t.Fatalf("validated with expired certificate: %v", err)
}

// 2. Try download with unauthorized certificate
art.Link = "https://localhost:43235/test.txt"
if err := downloadArtifact(name, art, nil, "", "", make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, "", make(chan struct{})); err == nil {
t.Fatalf("validated with unauthorized certificate: %v", err)
}

// 3. Try download with unknown certificate
art.Link = "https://localhost:43236/test.txt"
if err := downloadArtifact(name, art, nil, extCert, extKey, make(chan struct{})); err == nil {
if err := downloadArtifact(name, art, nil, extCert, make(chan struct{})); err == nil {
t.Fatalf("validated with certificate, different than configured one: %v", err)
}
}
Expand Down
6 changes: 3 additions & 3 deletions internal/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type Module struct {
// 2. checksums#SHA1
// 3. checksums#SHA256
// 4. checksums#MD5
// 5. First downloadadle download#links#md5url
// 5. First downloadable download#links#md5url
// Links are simplified to simple list with download URIs without any links for MD5 hashes.
type Artifact struct {
FileName string `json:"fileName"`
Expand Down Expand Up @@ -211,7 +211,7 @@ func (st *Storage) ArchiveModule(dir string) error {
}

// DownloadModule artifacts to local storage.
func (st *Storage) DownloadModule(toDir string, module *Module, progress Progress, cert, key string) (err error) {
func (st *Storage) DownloadModule(toDir string, module *Module, progress Progress, serverCert string) (err error) {
logger.Debugf("Download module to directory: [%s]", toDir)
logger.Tracef("Module: %v", module)
if err = os.MkdirAll(toDir, 0755); err != nil {
Expand Down Expand Up @@ -240,7 +240,7 @@ func (st *Storage) DownloadModule(toDir string, module *Module, progress Progres
}

for _, sa := range module.Artifacts {
if err = downloadArtifact(filepath.Join(toDir, sa.FileName), sa, callback, cert, key, st.done); err != nil {
if err = downloadArtifact(filepath.Join(toDir, sa.FileName), sa, callback, serverCert, st.done); err != nil {
return err
}
}
Expand Down
4 changes: 2 additions & 2 deletions internal/storage/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func TestDownloadArchiveModule(t *testing.T) {
// 1. Download module without progress.
path := filepath.Join(store.DownloadPath, "0", "0")
m := &Module{Name: "name1", Version: "1", Artifacts: []*Artifact{art}}
if err := store.DownloadModule(path, m, nil, "", ""); err != nil {
if err := store.DownloadModule(path, m, nil, ""); err != nil {
t.Fatalf("fail to download module [Hash: %s, File: %s]: %v", art.HashValue, hex.EncodeToString(srv.data), err)
}
existence(filepath.Join(path, art.FileName), true, "[initial download]", t)
Expand All @@ -251,7 +251,7 @@ func TestDownloadArchiveModule(t *testing.T) {
// 3. Download previous module with progress.
path = filepath.Join(store.DownloadPath, "0", "1")
progress := func(percent int) { /* Do nothing. */ }
if err := store.DownloadModule(path, m, progress, "", ""); err != nil {
if err := store.DownloadModule(path, m, progress, ""); err != nil {
t.Errorf("fail to download module: %v", err)
}
existence(filepath.Join(store.ModulesPath, "0", art.FileName), false, "[archive]", t)
Expand Down
2 changes: 1 addition & 1 deletion internal/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func mockScriptBasedSoftwareUpdatable(t *testing.T, tc *testConfig) (*ScriptBase

// Initialize mocked ScriptBasedSoftwareUpdatable
if err := feature.init(&ScriptBasedSoftwareUpdatableConfig{
Broker: getDefaultFlagValue(flagFeatureID),
Broker: getDefaultFlagValue(flagBroker),
FeatureID: tc.featureID,
ModuleType: getDefaultFlagValue(flagModuleType),
}, &edgeConfiguration{
Expand Down
Loading

0 comments on commit 89b70f2

Please sign in to comment.