diff --git a/common.go b/common.go index 9a406b7..05146b3 100644 --- a/common.go +++ b/common.go @@ -5,8 +5,6 @@ import ( ) const ( - magic uint32 = 0xfeedfeed - version01 uint32 = 1 version02 uint32 = 2 @@ -14,6 +12,8 @@ const ( trustedCertificateTag uint32 = 2 ) +var jksMagicBytes = []byte{0xfe, 0xed, 0xfe, 0xed} + var byteOrder = binary.BigEndian var whitenerMessage = []byte("Mighty Aphrodite") diff --git a/go.mod b/go.mod index 430601f..82f105e 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,11 @@ go 1.22.7 require github.com/stretchr/testify v1.9.0 +require golang.org/x/crypto v0.11.0 // indirect + require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + software.sslmate.com/src/go-pkcs12 v0.5.0 ) diff --git a/go.sum b/go.sum index 60ce688..5f50e9f 100644 --- a/go.sum +++ b/go.sum @@ -4,7 +4,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +software.sslmate.com/src/go-pkcs12 v0.5.0 h1:EC6R394xgENTpZ4RltKydeDUjtlM5drOYIG9c6TVj2M= +software.sslmate.com/src/go-pkcs12 v0.5.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/keystore.go b/keystore.go index 6567680..9f61ee3 100644 --- a/keystore.go +++ b/keystore.go @@ -1,7 +1,6 @@ package keystore import ( - "bytes" "crypto/rand" "crypto/sha1" "errors" @@ -109,7 +108,7 @@ func (ks KeyStore) Store(w io.Writer, password []byte) error { return fmt.Errorf("update digest with whitener message: %w", err) } - if err := e.writeUint32(magic); err != nil { + if err := e.writeBytes(jksMagicBytes); err != nil { return fmt.Errorf("write magic: %w", err) } // always write latest version @@ -143,67 +142,6 @@ func (ks KeyStore) Store(w io.Writer, password []byte) error { return nil } -// Load reads keystore representation from r and checks its signature. -// It is strongly recommended to fill password slice with zero after usage. -func (ks KeyStore) Load(r io.Reader, password []byte) error { - d := decoder{ - r: r, - h: sha1.New(), - } - - passwordBytes := passwordBytes(password) - defer zeroing(passwordBytes) - - if _, err := d.h.Write(passwordBytes); err != nil { - return fmt.Errorf("update digest with password: %w", err) - } - - if _, err := d.h.Write(whitenerMessage); err != nil { - return fmt.Errorf("update digest with whitener message: %w", err) - } - - readMagic, err := d.readUint32() - if err != nil { - return fmt.Errorf("read magic: %w", err) - } - - if readMagic != magic { - return errors.New("got invalid magic") - } - - version, err := d.readUint32() - if err != nil { - return fmt.Errorf("read version: %w", err) - } - - entryNum, err := d.readUint32() - if err != nil { - return fmt.Errorf("read number of entries: %w", err) - } - - for i := range entryNum { - alias, entry, err := d.readEntry(version) - if err != nil { - return fmt.Errorf("read %d entry: %w", i, err) - } - - ks.m[alias] = entry - } - - computedDigest := d.h.Sum(nil) - - actualDigest, err := d.readBytes(uint32(d.h.Size())) //nolint:gosec - if err != nil { - return fmt.Errorf("read digest: %w", err) - } - - if !bytes.Equal(actualDigest, computedDigest) { - return errors.New("got invalid digest") - } - - return nil -} - // SetPrivateKeyEntry adds PrivateKeyEntry into keystore by alias encrypted with password. // It is strongly recommended to fill password slice with zero after usage. func (ks KeyStore) SetPrivateKeyEntry(alias string, entry PrivateKeyEntry, password []byte) error { diff --git a/keystore_load.go b/keystore_load.go new file mode 100644 index 0000000..91c7141 --- /dev/null +++ b/keystore_load.go @@ -0,0 +1,132 @@ +package keystore + +import ( + "bytes" + "crypto/sha1" + "errors" + "fmt" + "io" + + "software.sslmate.com/src/go-pkcs12" +) + +// Load reads keystore representation from r and checks its signature. +// It is strongly recommended to fill password slice with zero after usage. +func (ks KeyStore) Load(r io.Reader, password []byte) error { + d := decoder{ + r: r, + h: sha1.New(), + } + + fourBytes, err := d.readBytes(4) //nolint:gomnd,mnd + if err != nil { + return fmt.Errorf("read magic: %w", err) + } + + magicBytesReader := bytes.NewReader(fourBytes) + fullReader := io.MultiReader(magicBytesReader, r) + + if bytes.Equal(fourBytes, jksMagicBytes) { + return ks.loadJks(fullReader, password) + } + + return ks.loadPkcs12(fullReader, password) +} + +// loads the old JKS format. +func (ks KeyStore) loadJks(r io.Reader, password []byte) error { + d := decoder{ + r: r, + h: sha1.New(), + } + + passwordBytes := passwordBytes(password) + defer zeroing(passwordBytes) + + if _, err := d.h.Write(passwordBytes); err != nil { + return fmt.Errorf("update digest with password: %w", err) + } + + if _, err := d.h.Write(whitenerMessage); err != nil { + return fmt.Errorf("update digest with whitener message: %w", err) + } + + fourBytes, err := d.readBytes(4) //nolint:gomnd,mnd + if err != nil { + return fmt.Errorf("read magic: %w", err) + } + + if !bytes.Equal(fourBytes, jksMagicBytes) { + return errors.New("got invalid magic bytes from the file, this is no JKS format") + } + + version, err := d.readUint32() + if err != nil { + return fmt.Errorf("read version: %w", err) + } + + entryNum, err := d.readUint32() + if err != nil { + return fmt.Errorf("read number of entries: %w", err) + } + + for i := range entryNum { + alias, entry, err := d.readEntry(version) + if err != nil { + return fmt.Errorf("read %d entry: %w", i, err) + } + + ks.m[alias] = entry + } + + computedDigest := d.h.Sum(nil) + + actualDigest, err := d.readBytes(uint32(d.h.Size())) //nolint:gosec + if err != nil { + return fmt.Errorf("read digest: %w", err) + } + + if !bytes.Equal(actualDigest, computedDigest) { + return errors.New("got invalid digest") + } + + return nil +} + +// loads the newer PKCS12 format. +func (ks KeyStore) loadPkcs12(r io.Reader, password []byte) error { + allData, err := io.ReadAll(r) + if err != nil { + return fmt.Errorf("can't read pkcs12 data: %w", err) + } + + certs, err := pkcs12.DecodeTrustStore(allData, string(password)) + if err != nil { + return fmt.Errorf("can't decode pkcs12 trust strore: %w", err) + } + + for _, cert := range certs { + certificate := Certificate{ + Type: "X509", + Content: nil, + } + + tce := TrustedCertificateEntry{} + tce.CreationTime = cert.NotBefore // there is no better timestamp provided by pkcs12 file + tce.Certificate = certificate + alias := fmt.Sprintf("c_%s,o_%s,ou_%s,cn_%s,s_%s", + cert.Subject.Country, + cert.Subject.Organization, + cert.Subject.OrganizationalUnit, + cert.Subject.CommonName, + cert.Subject.SerialNumber, + ) + // Country, Organization, OrganizationalUnit []string + // Locality, Province []string + // StreetAddress, PostalCode []string + // SerialNumber, CommonName string + ks.m[ks.convertAlias(alias)] = tce + } + + return nil +} diff --git a/keystore_load_test.go b/keystore_load_test.go new file mode 100644 index 0000000..aeb0997 --- /dev/null +++ b/keystore_load_test.go @@ -0,0 +1,213 @@ +package keystore + +import ( + "bytes" + _ "embed" + "encoding/pem" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLoad(t *testing.T) { + password := []byte{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'} + defer zeroing(password) + + f, err := os.Open("./testdata/keystore.jks") + require.NoError(t, err) + + defer func() { + err := f.Close() + require.NoError(t, err) + }() + + keyStore := New() + + err = keyStore.Load(f, password) + require.NoError(t, err) + + actualPKE, err := keyStore.GetPrivateKeyEntry("alias", password) + require.NoError(t, err) + + expectedCT, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "2017-09-19 17:41:00.016 +0300 EEST") + require.NoError(t, err) + + assert.Truef(t, actualPKE.CreationTime.Equal(expectedCT), + "unexpected private key entry creation time: '%v' '%v'", actualPKE.CreationTime, expectedCT) + + assert.Empty(t, actualPKE.CertificateChain, "unexpected private key entry certificate chain length") + + pkPEM, err := os.ReadFile("./testdata/key.pem") + require.NoError(t, err) + + decodedPK, _ := pem.Decode(pkPEM) + + assert.Equal(t, decodedPK.Bytes, actualPKE.PrivateKey, "unexpected private key") +} + +func TestLoadKeyPassword(t *testing.T) { + password := []byte{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'} + defer zeroing(password) + + keyPassword := []byte{'k', 'e', 'y', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'} + defer zeroing(keyPassword) + + f, err := os.Open("./testdata/keystore_keypass.jks") + require.NoError(t, err) + + defer func() { + err := f.Close() + require.NoError(t, err) + }() + + keyStore := New() + + err = keyStore.Load(f, password) + require.NoError(t, err) + + actualPKE, err := keyStore.GetPrivateKeyEntry("alias", keyPassword) + require.NoError(t, err) + + expectedCT, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "2020-10-26 12:01:38.387 +0200 EET") + require.NoError(t, err) + + assert.Truef(t, actualPKE.CreationTime.Equal(expectedCT), + "unexpected private key entry creation time: '%v' '%v'", actualPKE.CreationTime, expectedCT) + + assert.Lenf(t, actualPKE.CertificateChain, 1, + "unexpected private key entry certificate chain length: '%d' '%d'", len(actualPKE.CertificateChain), 0) + + pkPEM, err := os.ReadFile("./testdata/key_keypass.pem") + require.NoError(t, err) + + decodedPK, _ := pem.Decode(pkPEM) + + assert.Equal(t, decodedPK.Bytes, actualPKE.PrivateKey, "unexpected private key") +} + +//go:embed testdata/java/adoptium_openjdk_21.0.4_lts/cacerts +var fileJavaTemurinOpenJdk21Cacerts []byte + +//go:embed testdata/java/adoptium_openjdk_23.0.1.11/cacerts +var fileJavaTemurinOpenJdk23Cacerts []byte + +//go:embed testdata/java/corretto-8.432.06.1/cacerts +var fileJavaCorretto8Cacerts []byte + +//go:embed testdata/java/corretto-11.0.25.9.1/cacerts +var fileJavaCorretto11Cacerts []byte + +//go:embed testdata/java/oracle_openjdk_17.0.6/cacerts +var fileJavaOracleOpenJdk17Cacerts []byte + +func TestLoadVariousJdkTruststores(t *testing.T) { + + tests := []struct { + name string + certData []byte + numberOfCertificates int + password string + }{ + { + name: "adoptium_openjdk_21.0.4_lts", + certData: fileJavaTemurinOpenJdk21Cacerts, + password: "", + numberOfCertificates: 148, + }, + { + name: "adoptium_openjdk_23.0.1.11", + certData: fileJavaTemurinOpenJdk23Cacerts, + password: "", + numberOfCertificates: 152, + }, + { + name: "corretto-8.432.06.1", + certData: fileJavaCorretto8Cacerts, + password: "changeit", + numberOfCertificates: 161, + }, + { + name: "corretto-11.0.25.9.1", + certData: fileJavaCorretto11Cacerts, + password: "changeit", + numberOfCertificates: 161, + }, + { + name: "oracle_openjdk_17.0.6", + certData: fileJavaOracleOpenJdk17Cacerts, + password: "changeit", + numberOfCertificates: 90, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + password := []byte(tt.password) + adoptiumOpenJdkKeystore := bytes.NewReader(tt.certData) + + keyStore := New() + err := keyStore.Load(adoptiumOpenJdkKeystore, password) + require.NoError(t, err) + + assert.Len(t, keyStore.Aliases(), tt.numberOfCertificates) + }) + } +} + +////go:embed testdata/certificate_chain/truststore.p12 +//var fileCertificateChainTruststoreP12 []byte +// +//func TestLoadPkcs12WithPassword(t *testing.T) { +// password := []byte("password") +// selfSignedCert := bytes.NewReader(fileCertificateChainTruststoreP12) +// +// keyStore := New() +// err := keyStore.Load(selfSignedCert, password) +// require.NoError(t, err) +// +// assert.Len(t, keyStore.Aliases(), 1) +//} + +//go:embed testdata/certificate_chain/example_signed_certificates_chain.p12 +var fileCertificateChainExampleSignedCertificateChainP12 []byte + +func TestLoadPkcs12WithCertficateChain(t *testing.T) { + password := []byte("password") + selfSignedCert := bytes.NewReader(fileCertificateChainExampleSignedCertificateChainP12) + + keyStore := New() + err := keyStore.Load(selfSignedCert, password) + require.NoError(t, err) + + assert.Len(t, keyStore.Aliases(), 2) + + for _, alias := range keyStore.Aliases() { + chain, err := keyStore.GetPrivateKeyEntryCertificateChain(alias) + require.NoError(t, err) + + assert.NotNil(t, chain) + } +} + +////go:embed testdata/x.p12 +//var x []byte + +//func TestX(t *testing.T) { +// password := []byte("password") +// selfSignedCert := bytes.NewReader(x) +// +// keyStore := New() +// err := keyStore.Load(selfSignedCert, password) +// require.NoError(t, err) +// +// //assert.Len(t, keyStore.Aliases(), 2) +// +// for _, alias := range keyStore.Aliases() { +// chain, err := keyStore.GetPrivateKeyEntryCertificateChain(alias) +// require.NoError(t, err) +// +// assert.NotNil(t, chain) +// } +//} diff --git a/keystore_test.go b/keystore_test.go index ed70d89..37969cd 100644 --- a/keystore_test.go +++ b/keystore_test.go @@ -144,82 +144,6 @@ func TestAliases(t *testing.T) { assert.Equal(t, expectedAliases, actualAliases) } -func TestLoad(t *testing.T) { - password := []byte{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'} - defer zeroing(password) - - f, err := os.Open("./testdata/keystore.jks") - require.NoError(t, err) - - defer func() { - err := f.Close() - require.NoError(t, err) - }() - - keyStore := New() - - err = keyStore.Load(f, password) - require.NoError(t, err) - - actualPKE, err := keyStore.GetPrivateKeyEntry("alias", password) - require.NoError(t, err) - - expectedCT, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "2017-09-19 17:41:00.016 +0300 EEST") - require.NoError(t, err) - - assert.Truef(t, actualPKE.CreationTime.Equal(expectedCT), - "unexpected private key entry creation time: '%v' '%v'", actualPKE.CreationTime, expectedCT) - - assert.Empty(t, actualPKE.CertificateChain, "unexpected private key entry certificate chain length") - - pkPEM, err := os.ReadFile("./testdata/key.pem") - require.NoError(t, err) - - decodedPK, _ := pem.Decode(pkPEM) - - assert.Equal(t, decodedPK.Bytes, actualPKE.PrivateKey, "unexpected private key") -} - -func TestLoadKeyPassword(t *testing.T) { - password := []byte{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'} - defer zeroing(password) - - keyPassword := []byte{'k', 'e', 'y', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'} - defer zeroing(keyPassword) - - f, err := os.Open("./testdata/keystore_keypass.jks") - require.NoError(t, err) - - defer func() { - err := f.Close() - require.NoError(t, err) - }() - - keyStore := New() - - err = keyStore.Load(f, password) - require.NoError(t, err) - - actualPKE, err := keyStore.GetPrivateKeyEntry("alias", keyPassword) - require.NoError(t, err) - - expectedCT, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "2020-10-26 12:01:38.387 +0200 EET") - require.NoError(t, err) - - assert.Truef(t, actualPKE.CreationTime.Equal(expectedCT), - "unexpected private key entry creation time: '%v' '%v'", actualPKE.CreationTime, expectedCT) - - assert.Lenf(t, actualPKE.CertificateChain, 1, - "unexpected private key entry certificate chain length: '%d' '%d'", len(actualPKE.CertificateChain), 0) - - pkPEM, err := os.ReadFile("./testdata/key_keypass.pem") - require.NoError(t, err) - - decodedPK, _ := pem.Decode(pkPEM) - - assert.Equal(t, decodedPK.Bytes, actualPKE.PrivateKey, "unexpected private key") -} - func readPrivateKey(t *testing.T) []byte { t.Helper() diff --git a/testdata/certificate_chain/example_signed_certificates_chain.p12 b/testdata/certificate_chain/example_signed_certificates_chain.p12 new file mode 100644 index 0000000..31de0b7 Binary files /dev/null and b/testdata/certificate_chain/example_signed_certificates_chain.p12 differ diff --git a/testdata/certificate_chain/example_signed_certificates_chain.png b/testdata/certificate_chain/example_signed_certificates_chain.png new file mode 100644 index 0000000..f92809e Binary files /dev/null and b/testdata/certificate_chain/example_signed_certificates_chain.png differ diff --git a/testdata/java/adoptium_openjdk_21.0.4_lts/cacerts b/testdata/java/adoptium_openjdk_21.0.4_lts/cacerts new file mode 100644 index 0000000..563a54e Binary files /dev/null and b/testdata/java/adoptium_openjdk_21.0.4_lts/cacerts differ diff --git a/testdata/java/adoptium_openjdk_23.0.1.11/cacerts b/testdata/java/adoptium_openjdk_23.0.1.11/cacerts new file mode 100644 index 0000000..031af5a Binary files /dev/null and b/testdata/java/adoptium_openjdk_23.0.1.11/cacerts differ diff --git a/testdata/java/corretto-11.0.25.9.1/cacerts b/testdata/java/corretto-11.0.25.9.1/cacerts new file mode 100644 index 0000000..9adcfb0 Binary files /dev/null and b/testdata/java/corretto-11.0.25.9.1/cacerts differ diff --git a/testdata/java/corretto-8.432.06.1/cacerts b/testdata/java/corretto-8.432.06.1/cacerts new file mode 100644 index 0000000..714cc9d Binary files /dev/null and b/testdata/java/corretto-8.432.06.1/cacerts differ diff --git a/testdata/java/oracle_openjdk_17.0.6/cacerts b/testdata/java/oracle_openjdk_17.0.6/cacerts new file mode 100644 index 0000000..765e0c1 Binary files /dev/null and b/testdata/java/oracle_openjdk_17.0.6/cacerts differ diff --git a/testdata/self_signed_certificate/README.md b/testdata/self_signed_certificate/README.md new file mode 100644 index 0000000..9a364c3 --- /dev/null +++ b/testdata/self_signed_certificate/README.md @@ -0,0 +1,41 @@ + +Purpose +------- + +This is a self-signed certificate, which is can be used for testing the `keystore-go` library. +It was created by using openssl CLI tool in an interactive terminal session. + +Requirements +------------ + +* OpenSSL 3+ (using 3.3.2 3 Sep 2024 (Library: OpenSSL 3.3.2 3 Sep 2024)) + + +Documentation, how the file were created +---------------------------------------- + +You need to open a terminal and enter these commands line by line: + +```shell +openssl genrsa -out key.pem 4096 +openssl req -new > cert.csr +openssl x509 -in cert.csr -out cert.pem -req -signkey key.pem -days 9999 +openssl pkcs12 -export -out cert.p12 -in cert.pem -inkey key.pem -passin pass:pass -passout pass:password -nokeys -jdktrust anyExtendedKeyUsage -name test-name -caname test-ca-name +``` +When `openssl req ...` asks you for some certificate subject information, enter the following values: + +```text +Enter PEM pass phrase:pass +Country Name (2 letter code) [AU]:de +State or Province Name (full name) [Some-State]:Brandenburg +Locality Name (eg, city) []:Potsdam +Organization Name (eg, company) [Internet Widgits Pty Ltd]:keystore-go +Organizational Unit Name (eg, section) []:github.com.pavlo-v-chernykh.keystore-go +Common Name (e.g. server FQDN or YOUR name) []:pavlo-v-chernykh.keystore-go +Email Address []:keystore-go@example.org + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []:pass +An optional company name []: +``` \ No newline at end of file diff --git a/testdata/self_signed_certificate/cert.csr b/testdata/self_signed_certificate/cert.csr new file mode 100644 index 0000000..15f691e --- /dev/null +++ b/testdata/self_signed_certificate/cert.csr @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIDJzCCAg8CAQAwgcwxCzAJBgNVBAYTAmRlMRQwEgYDVQQIDAtCcmFuZGVuYnVy +ZzEQMA4GA1UEBwwHUG90c2RhbTEUMBIGA1UECgwLa2V5c3RvcmUtZ28xMDAuBgNV +BAsMJ2dpdGh1Yi5jb20ucGF2bG8tdi1jaGVybnlraC5rZXlzdG9yZS1nbzElMCMG +A1UEAwwccGF2bG8tdi1jaGVybnlraC5rZXlzdG9yZS1nbzEmMCQGCSqGSIb3DQEJ +ARYXa2V5c3RvcmUtZ29AZXhhbXBsZS5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDhRLTMre0GATUnOAVVX37M7WkaMhIBddjluXROguo8FjAn/Z8B +21hguJ8/6rv9uPRuArmb/+JyHOg2Bwt21HiG8G24J7cqLzDTbdn8k0l2hj5GG34p +zIoqup9mND7IZ3h6sbehDWYiRDpS2QMATjCSGBKiH7eY18xMGK8LEiuWNV+VJIIv +V5m6ajkOKGYjjUR5BZb7QyEeb/FARmTM9u1UG7CqXRnDWLk1Cp6/r+Kn9cmJWAvB +28o4XEFibnCLCna7qUOVa4S44z9a1s5DUFNdWvhLztE6Qwb3a/ljaPQyjiucbm5E +80fmgiecMTWyiVGc9bHAbOT//fm8n0ic3cf1AgMBAAGgFTATBgkqhkiG9w0BCQcx +BgwEcGFzczANBgkqhkiG9w0BAQsFAAOCAQEAf0tmy8I+Z+itFFiT6E1fsg4OfESi +KMHszUB3DwoKaE0LJGJ+fdd4+3Yg1w5QQO49rtaPltmTobOkZG5S4fMpuC0fD6+n +4SCK1CnMo8NKvtgiDTiS+9Aan7LOoEzqSODRbG2GKag8JX598bpp7ryvQttsy2j4 +h7A1epykLt/ma7QF2fh4mTgZdS3FkFSHjycr4TjgZF4TPcWTmjfHBsM+kIQc+u2x +zeDf6VNHMnvJOYoc6rE00UvLwVQUncdYBNH9LA6s3iaPvyweRAjqSxU4pZOHSs4Q +uTVdInnYZPzWegK1iP0nU5qNfeE0E62ODayjBU8TScu+nZrgT7B/Hor2Eg== +-----END CERTIFICATE REQUEST----- diff --git a/testdata/self_signed_certificate/cert.p12 b/testdata/self_signed_certificate/cert.p12 new file mode 100644 index 0000000..428ab31 Binary files /dev/null and b/testdata/self_signed_certificate/cert.p12 differ diff --git a/testdata/self_signed_certificate/cert.pem b/testdata/self_signed_certificate/cert.pem new file mode 100644 index 0000000..84a23a0 --- /dev/null +++ b/testdata/self_signed_certificate/cert.pem @@ -0,0 +1,36 @@ +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIUf8zHtQCQF+TZjO/rGYQ6VVLonLowDQYJKoZIhvcNAQEL +BQAwgcwxCzAJBgNVBAYTAmRlMRQwEgYDVQQIDAtCcmFuZGVuYnVyZzEQMA4GA1UE +BwwHUG90c2RhbTEUMBIGA1UECgwLa2V5c3RvcmUtZ28xMDAuBgNVBAsMJ2dpdGh1 +Yi5jb20ucGF2bG8tdi1jaGVybnlraC5rZXlzdG9yZS1nbzElMCMGA1UEAwwccGF2 +bG8tdi1jaGVybnlraC5rZXlzdG9yZS1nbzEmMCQGCSqGSIb3DQEJARYXa2V5c3Rv +cmUtZ29AZXhhbXBsZS5vcmcwIBcNMjQxMDAyMTMwMTU5WhgPMjA1MjAyMTcxMzAx +NTlaMIHMMQswCQYDVQQGEwJkZTEUMBIGA1UECAwLQnJhbmRlbmJ1cmcxEDAOBgNV +BAcMB1BvdHNkYW0xFDASBgNVBAoMC2tleXN0b3JlLWdvMTAwLgYDVQQLDCdnaXRo +dWIuY29tLnBhdmxvLXYtY2hlcm55a2gua2V5c3RvcmUtZ28xJTAjBgNVBAMMHHBh +dmxvLXYtY2hlcm55a2gua2V5c3RvcmUtZ28xJjAkBgkqhkiG9w0BCQEWF2tleXN0 +b3JlLWdvQGV4YW1wbGUub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEApYjRiOHLQnvadGxINiuOVgbS5hBdhugKxzGg3pGiMwNgreOSdM492RvgZ53i +anGaRyAxGJHInKhifsTcL0Pzhr0HlZreRoG5vEzR3DdZmK4sL3N8itwR1OI28BSM +A9MoQwYwUrARvvGt5XxV53K0FB+t7knd9D3bSnoNwm/VXZ/ygnx/GPIy9n4Obn7m +RGxVG8ZENc7+kjUQJ3mK96tRe7j6c11B8fseA1X16NoX0fjfy2N0/1ctai3gBSQu +NUhQ1ZAEVk3iy6fMrYpwZAuIUZVPQzviYCABhJmVSSl1XGr0CNr0bT7MOqyDZJau +9mz1NvPwxssujv20SiqxiXrrH6WPTjjd5HhgjhV6TwTuljyZIWPBrMTRp30aZqTP +sUPTgoew5IDveXaZ+dFpIDJfxTHh/razDRrnShpj1/kSSlqt/HmmBTTFQrRdD50k +p6sBLqbGwukKKaU4DnQ6L98xUj9/6p0dHut2eA0sCMZjOVnDh/sPsDKADKTyqzgr +KZ6g6Nra59FapWwvETEV0MWHzNT0z10FnvCxwYE4ldQDSSU2Yscu9KmUNdNbDoar +0DqlTKWEpu4Cg+rpJDKg01yZI9E00sMLSDaNvsTnLovCV8UJo9Yx4NY4op642y86 +LvPz4C2yVwM0FaamEMRkcTS0jshl380GGGPnptIQZn8iYRcCAwEAAaMhMB8wHQYD +VR0OBBYEFD8n1rbUCbG6fz+saA+JmY5/XZ3SMA0GCSqGSIb3DQEBCwUAA4ICAQBJ +MPhckQD3lzzb0QCBtTGo4AXT26IUOGuaI+fNOxRaNGNbAdF2k1P3jhu7trJyvBBC +2JBbsISt3WnvRUPISdgl3kQMcii6OqHrFRul08bvmjE3/DtPlz81fiXV2NMHcj9V +2oysXNpaI6Qu9l0H4bHcDPwUmkD+oJc18Jy4xk5wiEc4r0ZmuQfNfSkFUZCx7ULa +tQMFdRuvKiOOWM2hmAvIRTxt8vxY0bukQLBJZZ9m3i2TrmZeaGjbVaj2EnC/8iug +vRXVM2r5oW2w58qfCCagjV7RfaZ8kQFTotj6r0u4FWIMigf6e3pUoy46vsHvVTqm +OhswTGV0r1S60bXXFrqcBIPTr5aw4BuxNeGRfh1qJh5JAFNLrIb0cTYLG5gKCEGd +ra2/WeIH57Y7r1cMLRKZ+RlggjtYD263Ih8vc11Jjoig777mKjMO1NV/ddfQGiPn +5DBzK8VMdoFXriJm00AoiESVdQV3rBMLsVk+BcT+p2ZiECwBydki5wecHG5d1wCq +t4LvxKAy+8fqwg9b5NUofHRD4ZaQSE5qMjL79xc6OrdrjDWEc6OxIH1G6bCBpoH3 +L0a5dXvl3VDAOkdJiXqluAFK12wAMmKTsiBwLXOO1/7VYDMFiczFjoxb9C3HZNvO +0srBAqp0ZhTxrqvgFWhjhMxBRl3mLvBtCUIFMJCv4Q== +-----END CERTIFICATE----- diff --git a/testdata/self_signed_certificate/key.pem b/testdata/self_signed_certificate/key.pem new file mode 100644 index 0000000..94feea7 --- /dev/null +++ b/testdata/self_signed_certificate/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +YWQoh5c8uQY9+lL5qw0Ej3BgEsPFyA== +-----END PRIVATE KEY----- diff --git a/testdata/self_signed_certificate/privkey.pem b/testdata/self_signed_certificate/privkey.pem new file mode 100644 index 0000000..9bfbd40 --- /dev/null +++ b/testdata/self_signed_certificate/privkey.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFJDBWBgkqhkiG9w0BBQ0wSTAxBgkqhkiG9w0BBQwwJAQQphmD9D6Uo8ilwmxH +QP13VAICCAAwDAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQICJuTMHNghTYEggTI +HmhV0OKT83thajIyyW7/4wfC161ysKE4HwqHUGUiELqrFT3aYUU+0KN8tzXweau3 +3a+mFPTzhfO6s1wHW7w83PGaHsfpLcV0gM4Bzy0jksSKj6xhxqSUAKlDuJPJLXoS +EVICIIbszHB3peIfxFA/SuyZcA808Y0rlxwIM4aCoawOvPpnBebgODF/n0AsdesN +FCMzEnbxS6n2JpRWyXpaYA5XnWGbWTGOfe6NwhL7dpcP2G/SfRd/WLlBdR42VGyE +GpgNQiSbj6iF9ZhzwU4sgXkl919VnXewV/yQn6vBRACauHrCAfUux5r76LHRN+en +pqiSCKaNRpO43nyBAJh6xub/aii1AETESVSwoErTuYy8eRnae8alhqgyEuyXlDSn +XWG4pQLYq1G3uumG12bWoDuXFoNv4SPygr/44g0zC4bozdvSw1058/yFyHOO5MPj +Wwtx1wwvnbGdIYCZXVEaaPbmBI3RiH/UQu7N/3U4tDY4e70DuRM5M/PgIv7IcDT4 +J292eRVucM30cz//4u+8ELgFUr8JvxDnWIuIoA/oZWeyk6pr9Iaj3kqyLimX1sIz +vu/VgreApWubl39C5LF7FPimOKj1DkpYG140ORHcwPkCEuD1gKyy0uffRxaPxo75 +wIzb3bf+bN88pinV3t4vv2Y3cDXOqQD3ddMTaKXzYueSGRw7BwebCZkolOST/Ge3 +lPOTMFko6x5Io4e9F/XTgzi7JP4X62Sh4jCyUMSjUGtPEtJrWd/n/SmfV4LLCic+ +c1pIOSDS5jFwbquH2gZR+YPcPhFe93HQbMn8NXtTQ+PRPESoMtTdsVpKEqHrLm8V +B8bjiZd/AC47mcrnDFIuHdk1CDCSW9F+0MwitGChg0FCsALVoehlQWk/gQAJqI6P +j99/Ej07s0iE2n56wuy0szwPhY8rhLLdV05P2oMLlrIqOFX1tf/d2Gp84t1G5LqH +5aeZwpswsDY/F5Wd6KqQrf9ExHDQsXoj5d8q4U/5AtB6wyAoBbhYGA5loKq29opb +FnJJtyY/GOjQTFXz7YdgQ+alNp8XUcaMN+Lv23VLbJ1zvQ0J67+tZ6sFxP3BbDEt +PItN0kOo90C1e5ysvT9MBsYVF/eGwzFUzyDLVvxPx5PRbYOBEnI5llUY08+aEu7v +6AHJ0jhVTKOR+HdQ8y0STjReuJmfllYUgR/MEPoGydMyB0vhHqHwHjcWGX6OBnDh +BMTp+vR8Bn5qZKaIxBuPtP4n4H0YEidUKHsKk5IrMj74epTYbsBVJJVMq3MGX8Si +fJYCv3pyVq3csisYAJnIwQGBt75wGd6t9h3ccQ9F82gXND0RssGwB2alOvSQmt25 +097LMjky6AXTc9jLiN/+Sbf53HMl6egUSGe4SBI7MIJvKQU8F62mbLT40IN7pFax +ad4FGwQLMa8RxjrY0bsUbfW2zTyxpCkgVCVy/pEYUS8y6OpA60gj1WtlkVs3NI8n +2mTOv9/OXWzS5die0cNHlyss/yf14wZTeY7OGtAaLLhM3vm92gNA8ICLPklqKdvt +rnmBN7Saoj4gfIp+gx2LV5X6eDgopLOe3ZwdoTdC6DMNIohoYzoBMJ26mx71duqa +3MnZQXqECo4IvUSlXor956krCkhu3owp +-----END ENCRYPTED PRIVATE KEY-----