Skip to content

Commit

Permalink
Merge pull request #83 from zhiburt/patch-tls-certs
Browse files Browse the repository at this point in the history
Add TLS certs support for mutual authentication
  • Loading branch information
kursataktas committed Oct 15, 2022
2 parents eddadbb + 8f37147 commit e53cd98
Show file tree
Hide file tree
Showing 8 changed files with 863 additions and 30 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ ddosify [FLAG]
| `-l` | [Type](#load-types) of the load test. Ddosify supports 3 load types. | `string` | `linear` | No |
| <span style="white-space: nowrap;">`--config`</span> | [Config File](#config-file) of the load test. | `string` | - | No |
| <span style="white-space: nowrap;">`--version`</span> | Prints version, git commit, built date (utc), go information and quit | - | - | No |

| <span style="white-space: nowrap;">`--cert_path`</span> | A path to a certificate file (usually called 'cert.pem') | - | - | No |
| <span style="white-space: nowrap;">`--cert_key_path`</span> | A path to a certificate key file (usually called 'key.pem') | - | - | No |

### Load Types

Expand Down
19 changes: 17 additions & 2 deletions config/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ type step struct {
Timeout int `json:"timeout"`
Sleep string `json:"sleep"`
Others map[string]interface{} `json:"others"`
CertPath string `json:"cert_path"`
CertKeyPath string `json:"cert_key_path"`
}

func (s *step) UnmarshalJSON(data []byte) error {
Expand Down Expand Up @@ -220,7 +222,8 @@ func stepToScenarioItem(s step) (types.ScenarioItem, error) {
}

s.Protocol = strings.ToUpper(s.Protocol)
return types.ScenarioItem{

item := types.ScenarioItem{
ID: s.Id,
Name: s.Name,
URL: s.Url,
Expand All @@ -232,7 +235,19 @@ func stepToScenarioItem(s step) (types.ScenarioItem, error) {
Timeout: s.Timeout,
Sleep: strings.ReplaceAll(s.Sleep, " ", ""),
Custom: s.Others,
}, nil
}

if s.CertPath != "" && s.CertKeyPath != "" {
cert, pool, err := types.ParseTLS(s.CertPath, s.CertKeyPath)
if err != nil {
return item, err
}

item.Cert = cert
item.CertPool = pool
}

return item, nil
}

func prepareMultipartPayload(parts []multipartFormData) (body string, contentType string, err error) {
Expand Down
261 changes: 261 additions & 0 deletions config/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
package config

import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"reflect"
"regexp"
"strings"
Expand Down Expand Up @@ -303,3 +306,261 @@ func TestCreateHammerInvalidTarget(t *testing.T) {
t.Errorf("TestCreateHammerProtocol error occurred")
}
}

func TestCreateHammerTLS(t *testing.T) {
t.Parallel()

// prepare TLS files
cert, certKey := generateCerts()
certFile, keyFile, err := createCertPairFiles(cert, certKey)
if err != nil {
t.Fatalf("Failed to prepare certs %v", err)
}
defer os.Remove(certFile.Name())
defer os.Remove(keyFile.Name())

config := buildJSONTLSConfig(certFile.Name(), keyFile.Name())

jsonReader, _ := NewConfigReader(config, ConfigTypeJson)

h, err := jsonReader.CreateHammer()

if err != nil {
t.Errorf("TestCreateHammerDefaultValues error occurred: %v", err)
}

certVal, _, err := types.ParseTLS(certFile.Name(), keyFile.Name())
if err != nil {
t.Fatalf("Failed to gen certs %v", err)
}

// We compare only Certificte because CertPool has pointers inside and it's hard to compare it
if !reflect.DeepEqual(certVal, h.Scenario.Scenario[0].Cert) {
t.Errorf("\nExpected: %#v, \nFound: %#v", certVal, h.Scenario.Scenario[0].Cert)
}
}

func TestCreateHammerTLSWithOnlyCertPath(t *testing.T) {
t.Parallel()

// prepare TLS files
cert, certKey := generateCerts()
certFile, keyFile, err := createCertPairFiles(cert, certKey)
if err != nil {
t.Fatalf("Failed to prepare certs %v", err)
}
defer os.Remove(certFile.Name())
defer os.Remove(keyFile.Name())

config := buildJSONTLSConfig(certFile.Name(), "")

jsonReader, _ := NewConfigReader(config, ConfigTypeJson)
expectedHammer := types.Hammer{
TotalReqCount: types.DefaultReqCount,
LoadType: types.DefaultLoadType,
TestDuration: types.DefaultDuration,
ReportDestination: types.DefaultOutputType,
Scenario: types.Scenario{
Scenario: []types.ScenarioItem{{
ID: 1,
URL: strings.ToLower(types.DefaultProtocol) + "://test.com",
Protocol: types.DefaultProtocol,
Method: types.DefaultMethod,
Timeout: types.DefaultTimeout,
}},
},
Proxy: proxy.Proxy{
Strategy: proxy.ProxyTypeSingle,
},
}

h, err := jsonReader.CreateHammer()

if err != nil {
t.Errorf("TestCreateHammerDefaultValues error occurred: %v", err)
}

if !reflect.DeepEqual(expectedHammer, h) {
t.Errorf("\nExpected: %#v, \nFound: %#v", expectedHammer, h)
}
}

func TestCreateHammerTLSWithOnlyKeyPath(t *testing.T) {
t.Parallel()

// prepare TLS files
cert, certKey := generateCerts()
certFile, keyFile, err := createCertPairFiles(cert, certKey)
if err != nil {
t.Fatalf("Failed to prepare certs %v", err)
}
defer os.Remove(certFile.Name())
defer os.Remove(keyFile.Name())

config := buildJSONTLSConfig("", keyFile.Name())

jsonReader, _ := NewConfigReader(config, ConfigTypeJson)
expectedHammer := types.Hammer{
TotalReqCount: types.DefaultReqCount,
LoadType: types.DefaultLoadType,
TestDuration: types.DefaultDuration,
ReportDestination: types.DefaultOutputType,
Scenario: types.Scenario{
Scenario: []types.ScenarioItem{{
ID: 1,
URL: strings.ToLower(types.DefaultProtocol) + "://test.com",
Protocol: types.DefaultProtocol,
Method: types.DefaultMethod,
Timeout: types.DefaultTimeout,
}},
},
Proxy: proxy.Proxy{
Strategy: proxy.ProxyTypeSingle,
},
}

h, err := jsonReader.CreateHammer()

if err != nil {
t.Errorf("TestCreateHammerDefaultValues error occurred: %v", err)
}

if !reflect.DeepEqual(expectedHammer, h) {
t.Errorf("\nExpected: %#v, \nFound: %#v", expectedHammer, h)
}
}

func TestCreateHammerTLSWithWithEmptyPath(t *testing.T) {
t.Parallel()

config := buildJSONTLSConfig("", "")

jsonReader, _ := NewConfigReader(config, ConfigTypeJson)
expectedHammer := types.Hammer{
TotalReqCount: types.DefaultReqCount,
LoadType: types.DefaultLoadType,
TestDuration: types.DefaultDuration,
ReportDestination: types.DefaultOutputType,
Scenario: types.Scenario{
Scenario: []types.ScenarioItem{{
ID: 1,
URL: strings.ToLower(types.DefaultProtocol) + "://test.com",
Protocol: types.DefaultProtocol,
Method: types.DefaultMethod,
Timeout: types.DefaultTimeout,
}},
},
Proxy: proxy.Proxy{
Strategy: proxy.ProxyTypeSingle,
},
}

h, err := jsonReader.CreateHammer()

if err != nil {
t.Errorf("TestCreateHammerDefaultValues error occurred: %v", err)
}

if !reflect.DeepEqual(expectedHammer, h) {
t.Errorf("\nExpected: %#v, \nFound: %#v", expectedHammer, h)
}
}

func buildJSONTLSConfig(certPath, keyPath string) []byte {
format := `
{
"steps": [
{
"id": 1,
"url": "test.com",
"cert_path": %q,
"cert_key_path": %q
}
]
}`

config := fmt.Sprintf(format, certPath, keyPath)

fmt.Println(config)

return []byte(config)
}

func createCertPairFiles(cert string, certKey string) (*os.File, *os.File, error) {
certFile, err := os.CreateTemp("", ".pem")
if err != nil {
return nil, nil, err
}

_, err = io.WriteString(certFile, cert)
if err != nil {
return nil, nil, err
}

keyFile, err := os.CreateTemp("", ".pem")
if err != nil {
return nil, nil, err
}

_, err = io.WriteString(keyFile, certKey)
if err != nil {
return nil, nil, err
}

return certFile, keyFile, nil
}

func generateCerts() (string, string) {
cert := `-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUS4UhTks8aRCQ1k9IGn437ZyP3MgwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjEwMDUyMjM5MDVaFw0zMjEw
MDIyMjM5MDVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDMbZctKXBx8v63TXIhM/OB7S6VfPqpzfHufhs6kAHu
jfC2ooCUqzqdg0T8bM1bjahYuAbQA1cWKYBsqfd01Po1ltWmbMf7ZvmSB6VN7kC2
Y670zee91dGDQ2yzmorJuIZAtOBVZesYLg8UHSGzSC/smJOrjYidtlbvzOcX0pv3
RCIUrNMed60EpSch/rzAJLzJmwNSQZ4vJHNlNetSkvTi7cxMWfwpcM/rN1hEmP1X
J43hJp/TNRZVnEsvs/yggP/FwUjG74mU3KfnWiv91AkkarNTNquEMJ+f4OFqMcnF
p0wqg47JTqcAAT0n1B0VB+z0hGXEFMN+IJXsHETZNG+JAgMBAAGjUzBRMB0GA1Ud
DgQWBBSIw+qUKQJjXWti5x/Cnn2GueuX5zAfBgNVHSMEGDAWgBSIw+qUKQJjXWti
5x/Cnn2GueuX5zAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAA
DXzf8VXi4s2GScNfHf0BzMjpyrtRZ0Wbp2Vfh7OwVR6xcx+pqXNjlydM/vu2LvOK
hh7Jbo+JS+o7O24UJ9lLFkCRsZVF+NFqJf+2rdHCaOiZSdZmtjBU0dFuAGS7+lU3
M8P7WCNOm6NAKbs7VZHVcZPzp81SCPQgQIS19xRf4Irbvsijv4YdyL4Qv7aWcclb
MdZX9AH9Fx8tJq4VKvUYsCXAD0kuywMLjh+yj5O/2hMvs5rvaQvm2daQNRDNp884
uTLrNF7W7QaKEL06ZpXJoBqdKsiwn577XTDKvzN0XxQrT+xV9VHO7OXblF+Od3/Y
SzBR+QiQKy3x+LkOxhkk
-----END CERTIFICATE-----`

certKey := `-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMbZctKXBx8v63
TXIhM/OB7S6VfPqpzfHufhs6kAHujfC2ooCUqzqdg0T8bM1bjahYuAbQA1cWKYBs
qfd01Po1ltWmbMf7ZvmSB6VN7kC2Y670zee91dGDQ2yzmorJuIZAtOBVZesYLg8U
HSGzSC/smJOrjYidtlbvzOcX0pv3RCIUrNMed60EpSch/rzAJLzJmwNSQZ4vJHNl
NetSkvTi7cxMWfwpcM/rN1hEmP1XJ43hJp/TNRZVnEsvs/yggP/FwUjG74mU3Kfn
Wiv91AkkarNTNquEMJ+f4OFqMcnFp0wqg47JTqcAAT0n1B0VB+z0hGXEFMN+IJXs
HETZNG+JAgMBAAECggEAM+U6NHfJmNPD/8qER5OFpJ0Ob1qL06F5Yj7XMLWwF9wm
mGaGV7dkKOpTD/Wa6Dv82ZDWAeZnLDQa6vr228zZO9Nvp1EEL3kDsCOKvk7WVLbX
ikPfKZznE/iA1tNLmkvioPiJ3oQB+2Bt6YA/tuCDcf+FtU43uTm5tiSBIdYQS+Om
xN9OEXihk1svxHXQKa/a3nKPVLvdp3P90hDJ0PcRslXSy1V8az+A94JFEnCvnKsK
nF2rItCcXkInL0lYHZKgLHQMXGWkNl8e3PA1GZk3yF6LPNtPI1T5Ek9GwkHNw4JZ
BL/xEWLKB1qR2Z4I3UbWGVyi418kANv1eISb+49egQKBgQDraSRWB8nM5O3Zl9kT
8S5K924o1oXrO17eqQlVtQVmtUdoVvIBc6uHQZOmV1eHYpr6c95h8apNLexI22AY
SWkq9smpCnxLUsdkplwzie0F4bAzD6MCR8WIJxapUSPlyCA+8st1hquYBchKGQhd
6mMY1gzMDacYV/WhtG4E5d0nMQKBgQDeTr793n00VtpKuquFJe6Stu7Ujf64dL0s
3opLovyI0TmtMz5oCqIezwrjqc0Vy0UksWXaz0AboinDP+5n60cTEIt/6H0kryDc
dxfSHEA9BBDoQtxOFi3QGcxXbwu0i9QSoexrKY7FhA2xPji6bCcPycthhIrCpUiZ
s5gVkjHn2QKBgQCGklxLMbiSgGvXb46Qb9be1AMNJVT427+n2UmUzR6BUC+53boK
Sm1LrJkTBerrYdrmQUZnBxcrd40TORT9zTlpbhppn6zeAjwptVAPxlDQg+uNxOqS
ayToaC/0KoYy3OxSD8lvLcT56pRMh3LY/RwZHoPCQiu7Js0r21DpS93YgQKBgAuc
c09RMprsOmSS0WiX7ZkOIvVJIVfDCSpxySlgLu56dxe7yHOosoUHbVsswEB2KHtd
JKPEFWYcFzBSg4I8AK9XOuIIY5jp6L57Hexke1p0fumSrG0LrYLkBg8/Bo58iywZ
9v414nYgipKKXG4oPfYOJShHwvOdrGgSwEvIIgEpAoGAZz0yC9+x+JaoTnyUIRyI
+Aj5a4KhYjFtsZhcn/yCZHDqzJNDz6gAu579ey+J2CVOhjtgB5lowsDrHu32Hqnn
SEfyTru/ynQ8obwaRzdDYml+On86YWOw+brpMXkN+KB6bs2okE2N68v0qGPakxjt
OLDW6kKz5pI4T8lQJhdqjCU=
-----END PRIVATE KEY-----`

return cert, certKey
}
Loading

0 comments on commit e53cd98

Please sign in to comment.