From b9d33189702a88363c43b771593c110ffe653a17 Mon Sep 17 00:00:00 2001 From: Andjelko Iharos Date: Mon, 11 Dec 2023 11:17:51 +0100 Subject: [PATCH] MINOR: add more information fields to ssl_certificate New fields: Algorithm, AuthorityKeyID, Serial, Sha1FingerPrint, Sha256FingerPrint, Subject, SubjectAlternativeNames, SubjectKeyID --- models/ssl_certificate.go | 24 +++ models/ssl_certificate_compare.go | 64 ++++++++ models/ssl_certificate_compare_test.go | 4 +- specification/build/haproxy_spec.yaml | 16 ++ .../models/storage/ssl_certificate.yaml | 24 ++- storage/cert-info.go | 90 ++++++++++- storage/storage_test.go | 34 +++- .../test-certs/invalid/NOK-crt_key_int1.pem | 66 ++++++++ storage/test-certs/invalid/NOK-int1_int2.pem | 38 +++++ .../self-signed-without-rsa.pem | 0 .../test-certs/valid/OK-crt_key_int1_int2.pem | 85 ++++++++++ .../test-certs/valid/OK-int1_key_crt_int2.pem | 85 ++++++++++ .../test-certs/valid/OK-key_crt_int1_int2.pem | 148 +++++++++--------- 13 files changed, 586 insertions(+), 92 deletions(-) create mode 100644 storage/test-certs/invalid/NOK-crt_key_int1.pem create mode 100644 storage/test-certs/invalid/NOK-int1_int2.pem rename storage/test-certs/{valid => invalid}/self-signed-without-rsa.pem (100%) create mode 100644 storage/test-certs/valid/OK-crt_key_int1_int2.pem create mode 100644 storage/test-certs/valid/OK-int1_key_crt_int2.pem diff --git a/models/ssl_certificate.go b/models/ssl_certificate.go index fb2fae8e..6ba5097d 100644 --- a/models/ssl_certificate.go +++ b/models/ssl_certificate.go @@ -36,6 +36,12 @@ import ( // swagger:model ssl_certificate type SslCertificate struct { + // algorithm + Algorithm string `json:"algorithm,omitempty"` + + // authority key id + AuthorityKeyID string `json:"authority_key_id,omitempty"` + // description Description string `json:"description,omitempty"` @@ -64,12 +70,30 @@ type SslCertificate struct { // Format: date-time NotBefore *strfmt.DateTime `json:"not_before,omitempty" gorm:"type:timestamp with time zone"` + // serial + Serial string `json:"serial,omitempty"` + + // sha1 finger print + Sha1FingerPrint string `json:"sha1_finger_print,omitempty"` + + // sha256 finger print + Sha256FingerPrint string `json:"sha256_finger_print,omitempty"` + // File size in bytes. // Read Only: true Size *int64 `json:"size,omitempty"` // storage name StorageName string `json:"storage_name,omitempty"` + + // subject + Subject string `json:"subject,omitempty"` + + // subject alternative names + SubjectAlternativeNames string `json:"subject_alternative_names,omitempty"` + + // subject key id + SubjectKeyID string `json:"subject_key_id,omitempty"` } // Validate validates this ssl certificate diff --git a/models/ssl_certificate_compare.go b/models/ssl_certificate_compare.go index d8804018..d7d6fe10 100644 --- a/models/ssl_certificate_compare.go +++ b/models/ssl_certificate_compare.go @@ -37,6 +37,14 @@ import ( func (s SslCertificate) Equal(t SslCertificate, opts ...Options) bool { opt := getOptions(opts...) + if s.Algorithm != t.Algorithm { + return false + } + + if s.AuthorityKeyID != t.AuthorityKeyID { + return false + } + if s.Description != t.Description { return false } @@ -101,6 +109,18 @@ func (s SslCertificate) Equal(t SslCertificate, opts ...Options) bool { return false } + if s.Serial != t.Serial { + return false + } + + if s.Sha1FingerPrint != t.Sha1FingerPrint { + return false + } + + if s.Sha256FingerPrint != t.Sha256FingerPrint { + return false + } + if !equalPointers(s.Size, t.Size) { return false } @@ -109,6 +129,18 @@ func (s SslCertificate) Equal(t SslCertificate, opts ...Options) bool { return false } + if s.Subject != t.Subject { + return false + } + + if s.SubjectAlternativeNames != t.SubjectAlternativeNames { + return false + } + + if s.SubjectKeyID != t.SubjectKeyID { + return false + } + return true } @@ -129,6 +161,14 @@ func (s SslCertificate) Diff(t SslCertificate, opts ...Options) map[string][]int opt := getOptions(opts...) diff := make(map[string][]interface{}) + if s.Algorithm != t.Algorithm { + diff["Algorithm"] = []interface{}{s.Algorithm, t.Algorithm} + } + + if s.AuthorityKeyID != t.AuthorityKeyID { + diff["AuthorityKeyID"] = []interface{}{s.AuthorityKeyID, t.AuthorityKeyID} + } + if s.Description != t.Description { diff["Description"] = []interface{}{s.Description, t.Description} } @@ -193,6 +233,18 @@ func (s SslCertificate) Diff(t SslCertificate, opts ...Options) map[string][]int diff["NotBefore"] = []interface{}{ValueOrNil(s.NotBefore), ValueOrNil(t.NotBefore)} } + if s.Serial != t.Serial { + diff["Serial"] = []interface{}{s.Serial, t.Serial} + } + + if s.Sha1FingerPrint != t.Sha1FingerPrint { + diff["Sha1FingerPrint"] = []interface{}{s.Sha1FingerPrint, t.Sha1FingerPrint} + } + + if s.Sha256FingerPrint != t.Sha256FingerPrint { + diff["Sha256FingerPrint"] = []interface{}{s.Sha256FingerPrint, t.Sha256FingerPrint} + } + if !equalPointers(s.Size, t.Size) { diff["Size"] = []interface{}{ValueOrNil(s.Size), ValueOrNil(t.Size)} } @@ -201,5 +253,17 @@ func (s SslCertificate) Diff(t SslCertificate, opts ...Options) map[string][]int diff["StorageName"] = []interface{}{s.StorageName, t.StorageName} } + if s.Subject != t.Subject { + diff["Subject"] = []interface{}{s.Subject, t.Subject} + } + + if s.SubjectAlternativeNames != t.SubjectAlternativeNames { + diff["SubjectAlternativeNames"] = []interface{}{s.SubjectAlternativeNames, t.SubjectAlternativeNames} + } + + if s.SubjectKeyID != t.SubjectKeyID { + diff["SubjectKeyID"] = []interface{}{s.SubjectKeyID, t.SubjectKeyID} + } + return diff } diff --git a/models/ssl_certificate_compare_test.go b/models/ssl_certificate_compare_test.go index 027fcf66..9ee4b129 100644 --- a/models/ssl_certificate_compare_test.go +++ b/models/ssl_certificate_compare_test.go @@ -178,7 +178,7 @@ func TestSslCertificateDiffFalse(t *testing.T) { for _, sample := range samples { result := sample.a.Diff(sample.b) - if len(result) != 9 { + if len(result) != 17 { json := jsoniter.ConfigCompatibleWithStandardLibrary a, err := json.Marshal(&sample.a) if err != nil { @@ -188,7 +188,7 @@ func TestSslCertificateDiffFalse(t *testing.T) { if err != nil { t.Errorf(err.Error()) } - t.Errorf("Expected SslCertificate to be different in 9 cases, but it is not (%d) %s %s", len(result), a, b) + t.Errorf("Expected SslCertificate to be different in 17 cases, but it is not (%d) %s %s", len(result), a, b) } } } diff --git a/specification/build/haproxy_spec.yaml b/specification/build/haproxy_spec.yaml index 02e2733c..2b16242a 100644 --- a/specification/build/haproxy_spec.yaml +++ b/specification/build/haproxy_spec.yaml @@ -8825,6 +8825,10 @@ definitions: ssl_certificate: description: A file containing one or more SSL/TLS certificates and keys properties: + algorithm: + type: string + authority_key_id: + type: string description: type: string domains: @@ -8853,6 +8857,12 @@ definitions: type: string x-go-custom-tag: gorm:"type:timestamp with time zone" x-nullable: true + serial: + type: string + sha1_finger_print: + type: string + sha256_finger_print: + type: string size: description: File size in bytes. readOnly: true @@ -8860,6 +8870,12 @@ definitions: x-nullable: true storage_name: type: string + subject: + type: string + subject_alternative_names: + type: string + subject_key_id: + type: string title: SSL File type: object ssl_certificates: diff --git a/specification/models/storage/ssl_certificate.yaml b/specification/models/storage/ssl_certificate.yaml index 116f9d05..a55df143 100644 --- a/specification/models/storage/ssl_certificate.yaml +++ b/specification/models/storage/ssl_certificate.yaml @@ -14,23 +14,31 @@ ssl_certificate: readOnly: true x-nullable: true description: File size in bytes. - not_after: + serial: + type: string + not_before: type: string format: date-time readOnly: true x-nullable: true x-go-custom-tag: gorm:"type:timestamp with time zone" - not_before: + not_after: type: string format: date-time readOnly: true x-nullable: true x-go-custom-tag: gorm:"type:timestamp with time zone" - issuers: + algorithm: + type: string + sha1_finger_print: + type: string + sha256_finger_print: + type: string + domains: type: string readOnly: true x-omitempty: true - domains: + issuers: type: string readOnly: true x-omitempty: true @@ -38,3 +46,11 @@ ssl_certificate: type: string readOnly: true x-omitempty: true + authority_key_id: + type: string + subject: + type: string + subject_alternative_names: + type: string + subject_key_id: + type: string diff --git a/storage/cert-info.go b/storage/cert-info.go index 41eedb73..867eb974 100644 --- a/storage/cert-info.go +++ b/storage/cert-info.go @@ -16,22 +16,42 @@ package storage import ( + "crypto/sha1" //nolint:gosec + "crypto/sha256" "crypto/x509" "encoding/pem" + "fmt" "strings" "time" ) // Information about stored certificates to be returned by the API. type CertificatesInfo struct { - NotAfter, NotBefore *time.Time - DNS, IPs, Issuers string + NotAfter, NotBefore *time.Time + DNS, IPs, Issuers string + AuthorityKeyID string + SubjectKeyID string + Serial string + Algorithm string + Sha1FingerPrint string + Sha256FingerPrint string + Subject string + SubjectAlternativeNames string } // Private struct to store unique info about multiple certificates. type certsInfo struct { - NotAfter, NotBefore time.Time - DNS, IPs, Issuers map[string]struct{} + NotAfter, NotBefore time.Time + DNS, IPs, Issuers map[string]struct{} + AuthorityKeyID string + SubjectKeyID string + Serial string + Algorithm string + Sha1FingerPrint string + Sha256FingerPrint string + Subject string + SubjectAlternativeNames []string + Certs []*x509.Certificate } func newCertsInfo() *certsInfo { @@ -59,6 +79,22 @@ func ParseCertificatesInfo(bundle []byte) (*CertificatesInfo, error) { bundle = rest } + crt, err := findLeafCertificate(ci.Certs) + if err == nil { + // Format the keys as OpenSSL does: hex digits in uppercase, colon-separated + ci.AuthorityKeyID = formatFingerprint(crt.AuthorityKeyId) + ci.SubjectKeyID = formatFingerprint(crt.SubjectKeyId) + ci.Serial = crt.SerialNumber.String() + ci.Algorithm = crt.SignatureAlgorithm.String() + // Format the fingerprint as OpenSSL does: hex digits in uppercase, colon-separated + fingerPrint := sha1.Sum(crt.Raw) //nolint:gosec + ci.Sha1FingerPrint = formatFingerprint(fingerPrint[:]) + fingerPrint256 := sha256.Sum256(crt.Raw) + ci.Sha256FingerPrint = formatFingerprint(fingerPrint256[:]) + ci.Subject = crt.Subject.CommonName + ci.SubjectAlternativeNames = crt.DNSNames + } + return ci.toCertificatesInfo(), nil } @@ -70,6 +106,8 @@ func (ci *certsInfo) parseCertificate(der []byte) error { return err } + ci.Certs = append(ci.Certs, crt) + // Only keep the earliest expiration date. if ci.NotAfter.IsZero() || crt.NotAfter.Before(ci.NotAfter) { ci.NotAfter = crt.NotAfter @@ -95,12 +133,50 @@ func (ci *certsInfo) parseCertificate(der []byte) error { return nil } +// formatFingerprint formats a byte array as: hex digits in uppercase, colon-separated +func formatFingerprint(fingerprint []byte) string { + parts := make([]string, len(fingerprint)) + for i, b := range fingerprint { + parts[i] = fmt.Sprintf("%02X", b) + } + return strings.Join(parts, ":") +} + +// findLeafCertificate returns the first leaf certificate in the chain. +func findLeafCertificate(certs []*x509.Certificate) (*x509.Certificate, error) { + if len(certs) == 0 { + return nil, fmt.Errorf("empty certificate chain") + } + // Create a map to check if a certificate is someone else's issuer + isIssuer := make(map[string]bool) + for _, cert := range certs { + isIssuer[cert.Issuer.String()] = true + } + + // Find the starting certificate (a certificate whose issuer is not in the list) + for _, cert := range certs { + if !cert.IsCA && cert.Subject.CommonName != "" && !isIssuer[cert.Subject.String()] { + return cert, nil + } + } + + return nil, fmt.Errorf("no leaf certificate found") +} + // Transform a dirty *certsInfo into a clean *CertificatesInfo for the API. func (ci *certsInfo) toCertificatesInfo() *CertificatesInfo { csi := &CertificatesInfo{ - DNS: strings.Join(mapKeys(ci.DNS), ", "), - IPs: strings.Join(mapKeys(ci.IPs), ", "), - Issuers: strings.Join(mapKeys(ci.Issuers), ", "), + DNS: strings.Join(mapKeys(ci.DNS), ", "), + IPs: strings.Join(mapKeys(ci.IPs), ", "), + Issuers: strings.Join(mapKeys(ci.Issuers), ", "), + AuthorityKeyID: ci.AuthorityKeyID, + SubjectKeyID: ci.SubjectKeyID, + Serial: ci.Serial, + Algorithm: ci.Algorithm, + Sha1FingerPrint: ci.Sha1FingerPrint, + Sha256FingerPrint: ci.Sha256FingerPrint, + Subject: ci.Subject, + SubjectAlternativeNames: strings.Join(ci.SubjectAlternativeNames, ", "), } if !ci.NotAfter.IsZero() { csi.NotAfter = &ci.NotAfter diff --git a/storage/storage_test.go b/storage/storage_test.go index 6a2ff953..f4729f28 100644 --- a/storage/storage_test.go +++ b/storage/storage_test.go @@ -420,7 +420,7 @@ func Test_storage_validatePEM(t *testing.T) { validChain, err := readPem("valid/OK-key_crt_int1_int2.pem") require.NoError(t, err) - validSelfSignedWithoutRSA, err := readPem("valid/self-signed-without-rsa.pem") + validSelfSignedWithoutRSA, err := readPem("invalid/self-signed-without-rsa.pem") require.NoError(t, err) tests := []struct { @@ -470,33 +470,44 @@ func Test_storage_validatePEM(t *testing.T) { func Test_storage_getCertificatesInfo(t *testing.T) { tests := []struct { - name string dirname string filename string }{ { - name: "only public pem", filename: "only-public.pem", dirname: "invalid", }, { - name: "only private pem", filename: "only-private.pem", dirname: "invalid", }, { - name: "public, private and intermediate pems with correct order", + filename: "NOK-crt_key_int1.pem", + dirname: "invalid", + }, + { + filename: "NOK-int1_int2.pem", + dirname: "invalid", + }, + { + filename: "self-signed-without-rsa.pem", + dirname: "invalid", + }, + { filename: "OK-key_crt_int1_int2.pem", dirname: "valid", }, { - name: "self-signed cert without RSA", - filename: "self-signed-without-rsa.pem", + filename: "OK-crt_key_int1_int2.pem", + dirname: "valid", + }, + { + filename: "OK-int1_key_crt_int2.pem", dirname: "valid", }, } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { + t.Run(tt.filename, func(t *testing.T) { s := storage{ dirname: "../storage/test-certs/" + tt.dirname, } @@ -508,6 +519,13 @@ func Test_storage_getCertificatesInfo(t *testing.T) { t.Logf("%+v", info) return } + + if tt.dirname == "valid" { + require.NotEmpty(t, info.Sha1FingerPrint) + require.NotEmpty(t, info.Sha256FingerPrint) + require.NotEmpty(t, info.Subject) + require.NotEmpty(t, info.Serial) + } }) } } diff --git a/storage/test-certs/invalid/NOK-crt_key_int1.pem b/storage/test-certs/invalid/NOK-crt_key_int1.pem new file mode 100644 index 00000000..a6b5ff1f --- /dev/null +++ b/storage/test-certs/invalid/NOK-crt_key_int1.pem @@ -0,0 +1,66 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe6gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 +ZXJtMi4wHhcNMjMxMjEyMTI0ODUzWhcNMjQxMjExMTI0ODUzWjAYMRYwFAYDVQQD +DA0xLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +0rYEtRNxi0Zve2RteH3LgIR1CanLhOsW0fFaMqUtAE5g9uE7ZWW3qrKhi7gjf54t +xzIT/AxF8oTYr11xU/Anm9EdDgxvNLxFHO+LfIC/4HuFpNSzVrfoGUHTNljSfAJ7 +5paFD75N/sqLv3wlwaBvxVtP+8IlSJWUi0Uc8fPOvQD4s1OIeESOpJgKKhqLEUCD +/6JxhliKBksCaO2UYhc1ULmFr6RDh0ntApJL3vLnu7rx6Ri6Qnh1eLYgvRIZSVIP +RNY7i6uI54dD2Tg9gNf2m3y6cvVPBqlZtAzFZBdDIrCE4DTBOrvk3FbLug6rC+y9 +faZxNIFg4jR0FMPS8hrP7QIDAQABo18wXTAdBgNVHQ4EFgQUcUjcqhYUEMGUIjIO +aMq5fgH8CQMwPAYDVR0jBDUwM4AUv0NLKQCR3Xh6AMJK2WhreTrXwa2hF6QVMBMx +ETAPBgNVBAMMCEludGVybTEuggIQATANBgkqhkiG9w0BAQsFAAOCAQEAJqfYYRYG +Mg588gBMiyc3kRUuYOO1+rNqIJXXFVKxJQ2MLT5t4v82J9vX9bfrGg31o3pDCqHM +HUkuIG+4N8YNNPNMOXrNb07dQgfcIKU+CMaHDo8e7mzW0V2mC85ab7Jgsoq8Sl3N +K16YOf6Hl1zIzq5lMdNkTi1ug808QCzzACXv2I7TMxtufyzMUhfgGoynFnj0K2Dp +RnyDVfLk7DpP1HUlnbWLQzXyrDknuOImZchvCpAoTxKEi+K1GVzlaN83/WfsznA5 +lRrO1pTMHiWX4OvFxCaXJchjqGtmlP+SY2lNnZ9TGVVpwRG7F1G9oaZc5L/XdHcN +aQR1LwnihejSFA== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDStgS1E3GLRm97 +ZG14fcuAhHUJqcuE6xbR8VoypS0ATmD24TtlZbeqsqGLuCN/ni3HMhP8DEXyhNiv +XXFT8Ceb0R0ODG80vEUc74t8gL/ge4Wk1LNWt+gZQdM2WNJ8AnvmloUPvk3+you/ +fCXBoG/FW0/7wiVIlZSLRRzx8869APizU4h4RI6kmAoqGosRQIP/onGGWIoGSwJo +7ZRiFzVQuYWvpEOHSe0Ckkve8ue7uvHpGLpCeHV4tiC9EhlJUg9E1juLq4jnh0PZ +OD2A1/abfLpy9U8GqVm0DMVkF0MisITgNME6u+TcVsu6DqsL7L19pnE0gWDiNHQU +w9LyGs/tAgMBAAECggEABLqtmzPQbqq6H1KcdgxwEsEbpbJ1fSpP746Dcqi25xob +PodFGkGWGvhvPEUkf32DyQP/I1R82xSEuYDh0DC5xDCavpaPBhJmBGAoU7cfDLEx +CXH1rs//X1ZqdhPjG4Hsbns5NCaBC84sz0jVycVUT4wSXOlEBXTyqc03Y63QGXlU +4/X8/PdaFeIImqWpe8oKaviAEUIchkTPI6RrGUtYAWtX1f5tOSolOPGNyX4lyZ2L +TGbHuAfyndSAJ/lQad/EGUaKXLyXBD4nT1OAMIVKQ7VwVVH9Vg1zPvHPEZR+BqFj +VViey+gQZCQWZWyjmHm0c67oMQt3LY0pZ2N3d9Tv0QKBgQD+B6JwcY91FMjeXwQF +RlqhjFeLr/nXDc4T37fqTTHWr1jXLG7o6HpFQrToa8uFhJkALyXusurDFV4DCUFv +krB5toMdHx/dmXYGTTjW8PUrqznjeD4+je4XQvO95Cp+VpMlt6abQ5bGJtRdUs6g +k+UmiMX7cveAGTQ8M7YeK3fjMQKBgQDUWGBN2zmYG1csBd4Ylxoebz7wulyXJRm6 +1veMOb6jBrmWN/oZRDso6oATqImuv2g2vj4Em0lrAwkaj0HS4ofjjFP3DpYRSwzO +xfFby/om0WQ0cBfY9awUnWG32gnfiOgFGEpdC3WmMYDFetaRiKu5HfmdwBcEAtMt +rKkipTyxfQKBgQDU6m06NdR526voxlbGXQuFr+2IxTxxBb8eZTrvhTgqqtmZsEJd +sM0a1ChxTjhNdrAOuXXftdKTJIuhm9Zev+JugY0vkXDR+dg0u/DSJzA3I9LnV1dE +cw2GLbXCCUWcks/Oozlflaz/9He2qLtLV+qO+8CFWv0bPwTLGMSiUOixYQKBgF24 +J8EVGcVdg8rlSBH4VsnJ9bCPwB/hewqwqA9WySHw7OY1DIgsSiQT47VJdIMQ7bED +pCGqW+wEKfdz9OxbmPhATirDYE5/nkaArLcEPwL09dIDCzNxsqJil+dqL2NebHEb +OG76iNFyFdCTF7Kh7JDGfw414rKdgJEvHHMzFKeNAoGAfhWp5j2XxZy3Tv5hsA/I +DPWz8T6Sgw4joSQtq5TL/Hh7/6/SiH3bvmkvduOBEBFMXRqOpt24tEtPGfoDXAWf +w12ynnOD3o1bUuDR6k7Sj31gO5PtMarIhxecTBRuegbDlspXDSZfKIplmy29hsp2 +1X6qkVHc3N8m6VoiytdSyLw= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDETCCAfmgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHUm9v +dC1jYTAeFw0yMzEyMTIxMjQ4NTNaFw0yNDEyMTExMjQ4NTNaMBMxETAPBgNVBAMM +CEludGVybTEuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvB5DipKu +gd5NnqADoTc4WEoV3KQUOqgZmJP9QVL+KTjsKU9xmZi8fH6SqZiauke83PeSPh3F +8IsJ7xRO4nuX0kdKjlLtk+NLEEWRvpyyujKvBg8uvueuiwwVNKk0OQdLU5wKKrPg +N1c3JE3UNYSdkCfxsYOkQ5fBhNliORd2TvPlDpfVU5Po4WHOHInCiXNRGQZvUmvG +NiHdT1/G7XLVhyCtSB3xHvhUZvIQ/iyyzqKHYe7tiXg/agFV9wWD4LcfUdppsqkr +MxrMBGbO08D2m9dlrNulSox5gYdbEkOU8BwBAUB39PFJndSlAl8jq02aLfQvgm04 +qp8Sa1lO+iDfJQIDAQABo3AwbjAdBgNVHQ4EFgQUwD6viy8ijJuZ536ogAryjqt8 +jCowTQYDVR0jBEYwRIAUCtII33+Z/yDKfh4Q0MKK5ez94W2hFqQUMBIxEDAOBgNV +BAMMB1Jvb3QtY2GCFHDmRS7viAZ+qCvMmiBh1Z0tDXHsMA0GCSqGSIb3DQEBCwUA +A4IBAQCn4uxqWqpswSTGW7LWI4FQCrQfv30eTLiEcARwxySRyKsMAqW94ZXnnCm/ +ZKZ4KX9oPjWeIIMunbjSP+3UtoFrQP/rRfVod1XjtMk1F1yA3MsEE0iedvWNg3gG +mC3v7kT5HeYBkSdyLNvkyRpYAcJELNKdX/ZujiIBeuduY2KKNwrRLUX7R1saBAVj +3F75g4IwtRewpooTvmpijARBSCPTicWYYZ8AD+wniIt1vLYqXqTBhzxzm8whYiE1 +0fdp7D3C/tjdME/VZjNFLhO2Ofdu1FLLSy4vL46mu8w/+x73tSPFoEkJ6tuo4j4z +WzYYmIREK4cwQYopt5tzkzsWvSQ5 +-----END CERTIFICATE----- diff --git a/storage/test-certs/invalid/NOK-int1_int2.pem b/storage/test-certs/invalid/NOK-int1_int2.pem new file mode 100644 index 00000000..1e6cb8c9 --- /dev/null +++ b/storage/test-certs/invalid/NOK-int1_int2.pem @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE----- +MIIDETCCAfmgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHUm9v +dC1jYTAeFw0yMzEyMTIxMjQ4NTNaFw0yNDEyMTExMjQ4NTNaMBMxETAPBgNVBAMM +CEludGVybTEuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvB5DipKu +gd5NnqADoTc4WEoV3KQUOqgZmJP9QVL+KTjsKU9xmZi8fH6SqZiauke83PeSPh3F +8IsJ7xRO4nuX0kdKjlLtk+NLEEWRvpyyujKvBg8uvueuiwwVNKk0OQdLU5wKKrPg +N1c3JE3UNYSdkCfxsYOkQ5fBhNliORd2TvPlDpfVU5Po4WHOHInCiXNRGQZvUmvG +NiHdT1/G7XLVhyCtSB3xHvhUZvIQ/iyyzqKHYe7tiXg/agFV9wWD4LcfUdppsqkr +MxrMBGbO08D2m9dlrNulSox5gYdbEkOU8BwBAUB39PFJndSlAl8jq02aLfQvgm04 +qp8Sa1lO+iDfJQIDAQABo3AwbjAdBgNVHQ4EFgQUwD6viy8ijJuZ536ogAryjqt8 +jCowTQYDVR0jBEYwRIAUCtII33+Z/yDKfh4Q0MKK5ez94W2hFqQUMBIxEDAOBgNV +BAMMB1Jvb3QtY2GCFHDmRS7viAZ+qCvMmiBh1Z0tDXHsMA0GCSqGSIb3DQEBCwUA +A4IBAQCn4uxqWqpswSTGW7LWI4FQCrQfv30eTLiEcARwxySRyKsMAqW94ZXnnCm/ +ZKZ4KX9oPjWeIIMunbjSP+3UtoFrQP/rRfVod1XjtMk1F1yA3MsEE0iedvWNg3gG +mC3v7kT5HeYBkSdyLNvkyRpYAcJELNKdX/ZujiIBeuduY2KKNwrRLUX7R1saBAVj +3F75g4IwtRewpooTvmpijARBSCPTicWYYZ8AD+wniIt1vLYqXqTBhzxzm8whYiE1 +0fdp7D3C/tjdME/VZjNFLhO2Ofdu1FLLSy4vL46mu8w/+x73tSPFoEkJ6tuo4j4z +WzYYmIREK4cwQYopt5tzkzsWvSQ5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDADCCAeigAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 +ZXJtMS4wHhcNMjMxMjEyMTI0ODUzWhcNMjQxMjExMTI0ODUzWjATMREwDwYDVQQD +DAhJbnRlcm0yLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL+P3EUS +WLKC5AD95f1LDcIu4W96m+0ROq53xzxq4F30X+ivcGzfN05Hydu1VphvuOwMpyxW +RfLmlXLyigqnAwMMCCFUMf1HbETijRn0yOlNPlSDQba37TgK8AqQtNMA2qfx2rrw +WczYuIq4vwXhPH1u2qWjjBzy/ykxvn+s1PpZ/FPBXA8eawhHJbYLOTSghZQ98uVB +SSkKCP/LQKzhnPyB6B0+0h6EVGuTLou/PBBU5bufAOBJiufbhILRpEWeollx6gIC ++/T3pSxrMM2jc/jLo577CIlbcL5Hmu4NBMhaOLA1ffl4LWvxUxQuzPFqitNm9KP4 +5o3YyXMODVt3CtECAwEAAaNeMFwwHQYDVR0OBBYEFL9DSykAkd14egDCStloa3k6 +18GtMDsGA1UdIwQ0MDKAFMA+r4svIoybmed+qIAK8o6rfIwqoRakFDASMRAwDgYD +VQQDDAdSb290LWNhggIQADANBgkqhkiG9w0BAQsFAAOCAQEAfAjeG2/y6bVHVUi0 +j7wtn6VXiOPY7RTEXqFqU7GI//zUVFXntxaUxmlAoj5YRGwymLXDHULKLGVbo8RO +iHqzUDGDBztZpDyvt+5sPysaarvlS9D2x9Fw283uCuNuukv0Y9EoEufRvvleEXS6 +i4zLrH9cF7rlOpBkdBQRXQ+EMBiQYQtr/QIfHZ4dMUmf6KccW58HehBO3CfuFYem +y6cpNYlZAGkYWkn1ULhkNX4xhMiKjALUKPCwiRy9wOWQL09Af2gNEaXXiHdmYYq0 +WfIy55WwoGayIxRXywIK1VPI2mwK1EGF4+0qLatS0jgXpD9Jo2i0ZdZI57/KvmHd +5vpkpw== +-----END CERTIFICATE----- diff --git a/storage/test-certs/valid/self-signed-without-rsa.pem b/storage/test-certs/invalid/self-signed-without-rsa.pem similarity index 100% rename from storage/test-certs/valid/self-signed-without-rsa.pem rename to storage/test-certs/invalid/self-signed-without-rsa.pem diff --git a/storage/test-certs/valid/OK-crt_key_int1_int2.pem b/storage/test-certs/valid/OK-crt_key_int1_int2.pem new file mode 100644 index 00000000..95945b3c --- /dev/null +++ b/storage/test-certs/valid/OK-crt_key_int1_int2.pem @@ -0,0 +1,85 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe6gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 +ZXJtMi4wHhcNMjMxMjEyMTI0ODUzWhcNMjQxMjExMTI0ODUzWjAYMRYwFAYDVQQD +DA0xLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +0rYEtRNxi0Zve2RteH3LgIR1CanLhOsW0fFaMqUtAE5g9uE7ZWW3qrKhi7gjf54t +xzIT/AxF8oTYr11xU/Anm9EdDgxvNLxFHO+LfIC/4HuFpNSzVrfoGUHTNljSfAJ7 +5paFD75N/sqLv3wlwaBvxVtP+8IlSJWUi0Uc8fPOvQD4s1OIeESOpJgKKhqLEUCD +/6JxhliKBksCaO2UYhc1ULmFr6RDh0ntApJL3vLnu7rx6Ri6Qnh1eLYgvRIZSVIP +RNY7i6uI54dD2Tg9gNf2m3y6cvVPBqlZtAzFZBdDIrCE4DTBOrvk3FbLug6rC+y9 +faZxNIFg4jR0FMPS8hrP7QIDAQABo18wXTAdBgNVHQ4EFgQUcUjcqhYUEMGUIjIO +aMq5fgH8CQMwPAYDVR0jBDUwM4AUv0NLKQCR3Xh6AMJK2WhreTrXwa2hF6QVMBMx +ETAPBgNVBAMMCEludGVybTEuggIQATANBgkqhkiG9w0BAQsFAAOCAQEAJqfYYRYG +Mg588gBMiyc3kRUuYOO1+rNqIJXXFVKxJQ2MLT5t4v82J9vX9bfrGg31o3pDCqHM +HUkuIG+4N8YNNPNMOXrNb07dQgfcIKU+CMaHDo8e7mzW0V2mC85ab7Jgsoq8Sl3N +K16YOf6Hl1zIzq5lMdNkTi1ug808QCzzACXv2I7TMxtufyzMUhfgGoynFnj0K2Dp +RnyDVfLk7DpP1HUlnbWLQzXyrDknuOImZchvCpAoTxKEi+K1GVzlaN83/WfsznA5 +lRrO1pTMHiWX4OvFxCaXJchjqGtmlP+SY2lNnZ9TGVVpwRG7F1G9oaZc5L/XdHcN +aQR1LwnihejSFA== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDStgS1E3GLRm97 +ZG14fcuAhHUJqcuE6xbR8VoypS0ATmD24TtlZbeqsqGLuCN/ni3HMhP8DEXyhNiv +XXFT8Ceb0R0ODG80vEUc74t8gL/ge4Wk1LNWt+gZQdM2WNJ8AnvmloUPvk3+you/ +fCXBoG/FW0/7wiVIlZSLRRzx8869APizU4h4RI6kmAoqGosRQIP/onGGWIoGSwJo +7ZRiFzVQuYWvpEOHSe0Ckkve8ue7uvHpGLpCeHV4tiC9EhlJUg9E1juLq4jnh0PZ +OD2A1/abfLpy9U8GqVm0DMVkF0MisITgNME6u+TcVsu6DqsL7L19pnE0gWDiNHQU +w9LyGs/tAgMBAAECggEABLqtmzPQbqq6H1KcdgxwEsEbpbJ1fSpP746Dcqi25xob +PodFGkGWGvhvPEUkf32DyQP/I1R82xSEuYDh0DC5xDCavpaPBhJmBGAoU7cfDLEx +CXH1rs//X1ZqdhPjG4Hsbns5NCaBC84sz0jVycVUT4wSXOlEBXTyqc03Y63QGXlU +4/X8/PdaFeIImqWpe8oKaviAEUIchkTPI6RrGUtYAWtX1f5tOSolOPGNyX4lyZ2L +TGbHuAfyndSAJ/lQad/EGUaKXLyXBD4nT1OAMIVKQ7VwVVH9Vg1zPvHPEZR+BqFj +VViey+gQZCQWZWyjmHm0c67oMQt3LY0pZ2N3d9Tv0QKBgQD+B6JwcY91FMjeXwQF +RlqhjFeLr/nXDc4T37fqTTHWr1jXLG7o6HpFQrToa8uFhJkALyXusurDFV4DCUFv +krB5toMdHx/dmXYGTTjW8PUrqznjeD4+je4XQvO95Cp+VpMlt6abQ5bGJtRdUs6g +k+UmiMX7cveAGTQ8M7YeK3fjMQKBgQDUWGBN2zmYG1csBd4Ylxoebz7wulyXJRm6 +1veMOb6jBrmWN/oZRDso6oATqImuv2g2vj4Em0lrAwkaj0HS4ofjjFP3DpYRSwzO +xfFby/om0WQ0cBfY9awUnWG32gnfiOgFGEpdC3WmMYDFetaRiKu5HfmdwBcEAtMt +rKkipTyxfQKBgQDU6m06NdR526voxlbGXQuFr+2IxTxxBb8eZTrvhTgqqtmZsEJd +sM0a1ChxTjhNdrAOuXXftdKTJIuhm9Zev+JugY0vkXDR+dg0u/DSJzA3I9LnV1dE +cw2GLbXCCUWcks/Oozlflaz/9He2qLtLV+qO+8CFWv0bPwTLGMSiUOixYQKBgF24 +J8EVGcVdg8rlSBH4VsnJ9bCPwB/hewqwqA9WySHw7OY1DIgsSiQT47VJdIMQ7bED +pCGqW+wEKfdz9OxbmPhATirDYE5/nkaArLcEPwL09dIDCzNxsqJil+dqL2NebHEb +OG76iNFyFdCTF7Kh7JDGfw414rKdgJEvHHMzFKeNAoGAfhWp5j2XxZy3Tv5hsA/I +DPWz8T6Sgw4joSQtq5TL/Hh7/6/SiH3bvmkvduOBEBFMXRqOpt24tEtPGfoDXAWf +w12ynnOD3o1bUuDR6k7Sj31gO5PtMarIhxecTBRuegbDlspXDSZfKIplmy29hsp2 +1X6qkVHc3N8m6VoiytdSyLw= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDETCCAfmgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHUm9v +dC1jYTAeFw0yMzEyMTIxMjQ4NTNaFw0yNDEyMTExMjQ4NTNaMBMxETAPBgNVBAMM +CEludGVybTEuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvB5DipKu +gd5NnqADoTc4WEoV3KQUOqgZmJP9QVL+KTjsKU9xmZi8fH6SqZiauke83PeSPh3F +8IsJ7xRO4nuX0kdKjlLtk+NLEEWRvpyyujKvBg8uvueuiwwVNKk0OQdLU5wKKrPg +N1c3JE3UNYSdkCfxsYOkQ5fBhNliORd2TvPlDpfVU5Po4WHOHInCiXNRGQZvUmvG +NiHdT1/G7XLVhyCtSB3xHvhUZvIQ/iyyzqKHYe7tiXg/agFV9wWD4LcfUdppsqkr +MxrMBGbO08D2m9dlrNulSox5gYdbEkOU8BwBAUB39PFJndSlAl8jq02aLfQvgm04 +qp8Sa1lO+iDfJQIDAQABo3AwbjAdBgNVHQ4EFgQUwD6viy8ijJuZ536ogAryjqt8 +jCowTQYDVR0jBEYwRIAUCtII33+Z/yDKfh4Q0MKK5ez94W2hFqQUMBIxEDAOBgNV +BAMMB1Jvb3QtY2GCFHDmRS7viAZ+qCvMmiBh1Z0tDXHsMA0GCSqGSIb3DQEBCwUA +A4IBAQCn4uxqWqpswSTGW7LWI4FQCrQfv30eTLiEcARwxySRyKsMAqW94ZXnnCm/ +ZKZ4KX9oPjWeIIMunbjSP+3UtoFrQP/rRfVod1XjtMk1F1yA3MsEE0iedvWNg3gG +mC3v7kT5HeYBkSdyLNvkyRpYAcJELNKdX/ZujiIBeuduY2KKNwrRLUX7R1saBAVj +3F75g4IwtRewpooTvmpijARBSCPTicWYYZ8AD+wniIt1vLYqXqTBhzxzm8whYiE1 +0fdp7D3C/tjdME/VZjNFLhO2Ofdu1FLLSy4vL46mu8w/+x73tSPFoEkJ6tuo4j4z +WzYYmIREK4cwQYopt5tzkzsWvSQ5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDADCCAeigAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 +ZXJtMS4wHhcNMjMxMjEyMTI0ODUzWhcNMjQxMjExMTI0ODUzWjATMREwDwYDVQQD +DAhJbnRlcm0yLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL+P3EUS +WLKC5AD95f1LDcIu4W96m+0ROq53xzxq4F30X+ivcGzfN05Hydu1VphvuOwMpyxW +RfLmlXLyigqnAwMMCCFUMf1HbETijRn0yOlNPlSDQba37TgK8AqQtNMA2qfx2rrw +WczYuIq4vwXhPH1u2qWjjBzy/ykxvn+s1PpZ/FPBXA8eawhHJbYLOTSghZQ98uVB +SSkKCP/LQKzhnPyB6B0+0h6EVGuTLou/PBBU5bufAOBJiufbhILRpEWeollx6gIC ++/T3pSxrMM2jc/jLo577CIlbcL5Hmu4NBMhaOLA1ffl4LWvxUxQuzPFqitNm9KP4 +5o3YyXMODVt3CtECAwEAAaNeMFwwHQYDVR0OBBYEFL9DSykAkd14egDCStloa3k6 +18GtMDsGA1UdIwQ0MDKAFMA+r4svIoybmed+qIAK8o6rfIwqoRakFDASMRAwDgYD +VQQDDAdSb290LWNhggIQADANBgkqhkiG9w0BAQsFAAOCAQEAfAjeG2/y6bVHVUi0 +j7wtn6VXiOPY7RTEXqFqU7GI//zUVFXntxaUxmlAoj5YRGwymLXDHULKLGVbo8RO +iHqzUDGDBztZpDyvt+5sPysaarvlS9D2x9Fw283uCuNuukv0Y9EoEufRvvleEXS6 +i4zLrH9cF7rlOpBkdBQRXQ+EMBiQYQtr/QIfHZ4dMUmf6KccW58HehBO3CfuFYem +y6cpNYlZAGkYWkn1ULhkNX4xhMiKjALUKPCwiRy9wOWQL09Af2gNEaXXiHdmYYq0 +WfIy55WwoGayIxRXywIK1VPI2mwK1EGF4+0qLatS0jgXpD9Jo2i0ZdZI57/KvmHd +5vpkpw== +-----END CERTIFICATE----- diff --git a/storage/test-certs/valid/OK-int1_key_crt_int2.pem b/storage/test-certs/valid/OK-int1_key_crt_int2.pem new file mode 100644 index 00000000..eb1b28f2 --- /dev/null +++ b/storage/test-certs/valid/OK-int1_key_crt_int2.pem @@ -0,0 +1,85 @@ +-----BEGIN CERTIFICATE----- +MIIDETCCAfmgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHUm9v +dC1jYTAeFw0yMzEyMTIxMjQ4NTNaFw0yNDEyMTExMjQ4NTNaMBMxETAPBgNVBAMM +CEludGVybTEuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvB5DipKu +gd5NnqADoTc4WEoV3KQUOqgZmJP9QVL+KTjsKU9xmZi8fH6SqZiauke83PeSPh3F +8IsJ7xRO4nuX0kdKjlLtk+NLEEWRvpyyujKvBg8uvueuiwwVNKk0OQdLU5wKKrPg +N1c3JE3UNYSdkCfxsYOkQ5fBhNliORd2TvPlDpfVU5Po4WHOHInCiXNRGQZvUmvG +NiHdT1/G7XLVhyCtSB3xHvhUZvIQ/iyyzqKHYe7tiXg/agFV9wWD4LcfUdppsqkr +MxrMBGbO08D2m9dlrNulSox5gYdbEkOU8BwBAUB39PFJndSlAl8jq02aLfQvgm04 +qp8Sa1lO+iDfJQIDAQABo3AwbjAdBgNVHQ4EFgQUwD6viy8ijJuZ536ogAryjqt8 +jCowTQYDVR0jBEYwRIAUCtII33+Z/yDKfh4Q0MKK5ez94W2hFqQUMBIxEDAOBgNV +BAMMB1Jvb3QtY2GCFHDmRS7viAZ+qCvMmiBh1Z0tDXHsMA0GCSqGSIb3DQEBCwUA +A4IBAQCn4uxqWqpswSTGW7LWI4FQCrQfv30eTLiEcARwxySRyKsMAqW94ZXnnCm/ +ZKZ4KX9oPjWeIIMunbjSP+3UtoFrQP/rRfVod1XjtMk1F1yA3MsEE0iedvWNg3gG +mC3v7kT5HeYBkSdyLNvkyRpYAcJELNKdX/ZujiIBeuduY2KKNwrRLUX7R1saBAVj +3F75g4IwtRewpooTvmpijARBSCPTicWYYZ8AD+wniIt1vLYqXqTBhzxzm8whYiE1 +0fdp7D3C/tjdME/VZjNFLhO2Ofdu1FLLSy4vL46mu8w/+x73tSPFoEkJ6tuo4j4z +WzYYmIREK4cwQYopt5tzkzsWvSQ5 +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDStgS1E3GLRm97 +ZG14fcuAhHUJqcuE6xbR8VoypS0ATmD24TtlZbeqsqGLuCN/ni3HMhP8DEXyhNiv +XXFT8Ceb0R0ODG80vEUc74t8gL/ge4Wk1LNWt+gZQdM2WNJ8AnvmloUPvk3+you/ +fCXBoG/FW0/7wiVIlZSLRRzx8869APizU4h4RI6kmAoqGosRQIP/onGGWIoGSwJo +7ZRiFzVQuYWvpEOHSe0Ckkve8ue7uvHpGLpCeHV4tiC9EhlJUg9E1juLq4jnh0PZ +OD2A1/abfLpy9U8GqVm0DMVkF0MisITgNME6u+TcVsu6DqsL7L19pnE0gWDiNHQU +w9LyGs/tAgMBAAECggEABLqtmzPQbqq6H1KcdgxwEsEbpbJ1fSpP746Dcqi25xob +PodFGkGWGvhvPEUkf32DyQP/I1R82xSEuYDh0DC5xDCavpaPBhJmBGAoU7cfDLEx +CXH1rs//X1ZqdhPjG4Hsbns5NCaBC84sz0jVycVUT4wSXOlEBXTyqc03Y63QGXlU +4/X8/PdaFeIImqWpe8oKaviAEUIchkTPI6RrGUtYAWtX1f5tOSolOPGNyX4lyZ2L +TGbHuAfyndSAJ/lQad/EGUaKXLyXBD4nT1OAMIVKQ7VwVVH9Vg1zPvHPEZR+BqFj +VViey+gQZCQWZWyjmHm0c67oMQt3LY0pZ2N3d9Tv0QKBgQD+B6JwcY91FMjeXwQF +RlqhjFeLr/nXDc4T37fqTTHWr1jXLG7o6HpFQrToa8uFhJkALyXusurDFV4DCUFv +krB5toMdHx/dmXYGTTjW8PUrqznjeD4+je4XQvO95Cp+VpMlt6abQ5bGJtRdUs6g +k+UmiMX7cveAGTQ8M7YeK3fjMQKBgQDUWGBN2zmYG1csBd4Ylxoebz7wulyXJRm6 +1veMOb6jBrmWN/oZRDso6oATqImuv2g2vj4Em0lrAwkaj0HS4ofjjFP3DpYRSwzO +xfFby/om0WQ0cBfY9awUnWG32gnfiOgFGEpdC3WmMYDFetaRiKu5HfmdwBcEAtMt +rKkipTyxfQKBgQDU6m06NdR526voxlbGXQuFr+2IxTxxBb8eZTrvhTgqqtmZsEJd +sM0a1ChxTjhNdrAOuXXftdKTJIuhm9Zev+JugY0vkXDR+dg0u/DSJzA3I9LnV1dE +cw2GLbXCCUWcks/Oozlflaz/9He2qLtLV+qO+8CFWv0bPwTLGMSiUOixYQKBgF24 +J8EVGcVdg8rlSBH4VsnJ9bCPwB/hewqwqA9WySHw7OY1DIgsSiQT47VJdIMQ7bED +pCGqW+wEKfdz9OxbmPhATirDYE5/nkaArLcEPwL09dIDCzNxsqJil+dqL2NebHEb +OG76iNFyFdCTF7Kh7JDGfw414rKdgJEvHHMzFKeNAoGAfhWp5j2XxZy3Tv5hsA/I +DPWz8T6Sgw4joSQtq5TL/Hh7/6/SiH3bvmkvduOBEBFMXRqOpt24tEtPGfoDXAWf +w12ynnOD3o1bUuDR6k7Sj31gO5PtMarIhxecTBRuegbDlspXDSZfKIplmy29hsp2 +1X6qkVHc3N8m6VoiytdSyLw= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDBjCCAe6gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 +ZXJtMi4wHhcNMjMxMjEyMTI0ODUzWhcNMjQxMjExMTI0ODUzWjAYMRYwFAYDVQQD +DA0xLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +0rYEtRNxi0Zve2RteH3LgIR1CanLhOsW0fFaMqUtAE5g9uE7ZWW3qrKhi7gjf54t +xzIT/AxF8oTYr11xU/Anm9EdDgxvNLxFHO+LfIC/4HuFpNSzVrfoGUHTNljSfAJ7 +5paFD75N/sqLv3wlwaBvxVtP+8IlSJWUi0Uc8fPOvQD4s1OIeESOpJgKKhqLEUCD +/6JxhliKBksCaO2UYhc1ULmFr6RDh0ntApJL3vLnu7rx6Ri6Qnh1eLYgvRIZSVIP +RNY7i6uI54dD2Tg9gNf2m3y6cvVPBqlZtAzFZBdDIrCE4DTBOrvk3FbLug6rC+y9 +faZxNIFg4jR0FMPS8hrP7QIDAQABo18wXTAdBgNVHQ4EFgQUcUjcqhYUEMGUIjIO +aMq5fgH8CQMwPAYDVR0jBDUwM4AUv0NLKQCR3Xh6AMJK2WhreTrXwa2hF6QVMBMx +ETAPBgNVBAMMCEludGVybTEuggIQATANBgkqhkiG9w0BAQsFAAOCAQEAJqfYYRYG +Mg588gBMiyc3kRUuYOO1+rNqIJXXFVKxJQ2MLT5t4v82J9vX9bfrGg31o3pDCqHM +HUkuIG+4N8YNNPNMOXrNb07dQgfcIKU+CMaHDo8e7mzW0V2mC85ab7Jgsoq8Sl3N +K16YOf6Hl1zIzq5lMdNkTi1ug808QCzzACXv2I7TMxtufyzMUhfgGoynFnj0K2Dp +RnyDVfLk7DpP1HUlnbWLQzXyrDknuOImZchvCpAoTxKEi+K1GVzlaN83/WfsznA5 +lRrO1pTMHiWX4OvFxCaXJchjqGtmlP+SY2lNnZ9TGVVpwRG7F1G9oaZc5L/XdHcN +aQR1LwnihejSFA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDADCCAeigAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 +ZXJtMS4wHhcNMjMxMjEyMTI0ODUzWhcNMjQxMjExMTI0ODUzWjATMREwDwYDVQQD +DAhJbnRlcm0yLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL+P3EUS +WLKC5AD95f1LDcIu4W96m+0ROq53xzxq4F30X+ivcGzfN05Hydu1VphvuOwMpyxW +RfLmlXLyigqnAwMMCCFUMf1HbETijRn0yOlNPlSDQba37TgK8AqQtNMA2qfx2rrw +WczYuIq4vwXhPH1u2qWjjBzy/ykxvn+s1PpZ/FPBXA8eawhHJbYLOTSghZQ98uVB +SSkKCP/LQKzhnPyB6B0+0h6EVGuTLou/PBBU5bufAOBJiufbhILRpEWeollx6gIC ++/T3pSxrMM2jc/jLo577CIlbcL5Hmu4NBMhaOLA1ffl4LWvxUxQuzPFqitNm9KP4 +5o3YyXMODVt3CtECAwEAAaNeMFwwHQYDVR0OBBYEFL9DSykAkd14egDCStloa3k6 +18GtMDsGA1UdIwQ0MDKAFMA+r4svIoybmed+qIAK8o6rfIwqoRakFDASMRAwDgYD +VQQDDAdSb290LWNhggIQADANBgkqhkiG9w0BAQsFAAOCAQEAfAjeG2/y6bVHVUi0 +j7wtn6VXiOPY7RTEXqFqU7GI//zUVFXntxaUxmlAoj5YRGwymLXDHULKLGVbo8RO +iHqzUDGDBztZpDyvt+5sPysaarvlS9D2x9Fw283uCuNuukv0Y9EoEufRvvleEXS6 +i4zLrH9cF7rlOpBkdBQRXQ+EMBiQYQtr/QIfHZ4dMUmf6KccW58HehBO3CfuFYem +y6cpNYlZAGkYWkn1ULhkNX4xhMiKjALUKPCwiRy9wOWQL09Af2gNEaXXiHdmYYq0 +WfIy55WwoGayIxRXywIK1VPI2mwK1EGF4+0qLatS0jgXpD9Jo2i0ZdZI57/KvmHd +5vpkpw== +-----END CERTIFICATE----- diff --git a/storage/test-certs/valid/OK-key_crt_int1_int2.pem b/storage/test-certs/valid/OK-key_crt_int1_int2.pem index 4eff8c24..4f446df9 100644 --- a/storage/test-certs/valid/OK-key_crt_int1_int2.pem +++ b/storage/test-certs/valid/OK-key_crt_int1_int2.pem @@ -1,79 +1,85 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDozFWwRQY12oaK -+oZfLmyYpfBAx7x/gSobqpDOICSW4e/r28BJHDtFl0aFwUX8QEojXWlFhXQhH7aV -acHCeSYwI4GEb1SE0JtRo2ihOZ7EQfH15u/qROytV8HOnrIHDB7OGxpmLav2ID1i -xRE1hOp1AzTVqKnJZYvAciaDCGHi+QNvo7/p4aGSmwSD+ftvPbTQ1bDO+UGyJ17b -mblnSD3/ACu9JYNfvGzDzqMBrhGSllS7itPJY2ojNZ0b1iyQTciSmlTMbn8Lh0XJ -dWbkLSWeT7j0wW77ud7s0prUCIcbT3XCIFxhC+lkpVOFnRswXX/yPc7864do/4wN -5xGBsmk3AgMBAAECggEAY5W9dikgzfrMITmoL6FJXUdm7h9DWHvlim49gZ+oZ08B -djDMIbpM9KkQxvj1ukG6NUSpWs8K7XyGe4YBF/MBTghySDfjvOkL+DFh+c4PR786 -BUokCWAwqrpmsr+aQn+B0gMwGNOiwyfpeo34nZ9dOG8Fs/xxnTCuRsXOCbGVRiUU -0TpLgiPBEevwEhnuFZoTnWyPlqf92nki7SuLlhhY5rIb610zYedlPmP8cxxIII6x -XOWUOhGqnBWR/hvsjlSccDWXe0b/xCZ4LiHz7kJG1ZfxGurcHg8fZgazy7IGIInQ -km8/UA4jhdo2tpeNTA7Ops+AYx+lT68USgrWorxikQKBgQD6NLh+QdRE3SO5Bz/Z -OiY04IWJ+M+8Erepf9ZNHMwIOcuhpmgiaDtCnAor0DQf//EUsLUrrnGKhc5maOuf -CqPvmZL0Za/JytSTAdXV5DCOviYOPdUaRlYR1bqQFdlTJKUhKwjhHluD43AnV4nh -amihlU4BHy7wgCHf9YjWJQ5lnwKBgQDuMGqyggtzpmYnvL0N0jcOWR9HtTFAa6SV -wHE+BB5wdS1bQir1Wg/u9UlnEPYzv/dsvD/7Z84eIYiUSjvvb668J9PCZF3LrZ2h -DNajNxon92B+qm6CKA9w0MyU0zA324b49DKTqC5QVo6gzvyps2/fLeGJ/t2BHnbC -2YGOJG1laQKBgQDlnOI+w8y4UbTJxZRblpifZ/hE0Pha4VZ5D58r7yRy3A86zsq7 -4KmZjDdtU8myICAu26e3aYQ7GmZ65whsUMh3Rpls/bCf4CrKqiGCA8JoDKpB4Y6i -aS/teBWYyuRA/90mnias6T4Uv/EZuaUIH63bs3f9YY+jGAN+Uwb7dtBKgwKBgHEF -BkvHixmINmbalrZNLhSf00jaQBF6QjFQjCtKFwtzfl8UCYA8CN1xBDBkiv5JM2Uj -+hQX0GTZso3yn3fgfYAIQeG2cA8qRWZayinOBpo6Nk5EHoWh7pmwabKgdvu6LdRJ -QwpvPfKe77R8IsV/QDEc+yzYg1A2HVIdlOzWehYpAoGBAOxqMypISzjorP08w51D -MebIt6RhixBjzgJfZpfPdQnpu2o0ozsWwF4yaHSHox7g0cvxL/KqLHu7uxvzteQV -W7/ZJq2kNgN+rPddQ7kOw2227iuxo0HuHGCANUt/g25iKpIoEvDlQShw1l52iM05 -lgwhfR1KnD4wGAq8pKd7J21Z +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDStgS1E3GLRm97 +ZG14fcuAhHUJqcuE6xbR8VoypS0ATmD24TtlZbeqsqGLuCN/ni3HMhP8DEXyhNiv +XXFT8Ceb0R0ODG80vEUc74t8gL/ge4Wk1LNWt+gZQdM2WNJ8AnvmloUPvk3+you/ +fCXBoG/FW0/7wiVIlZSLRRzx8869APizU4h4RI6kmAoqGosRQIP/onGGWIoGSwJo +7ZRiFzVQuYWvpEOHSe0Ckkve8ue7uvHpGLpCeHV4tiC9EhlJUg9E1juLq4jnh0PZ +OD2A1/abfLpy9U8GqVm0DMVkF0MisITgNME6u+TcVsu6DqsL7L19pnE0gWDiNHQU +w9LyGs/tAgMBAAECggEABLqtmzPQbqq6H1KcdgxwEsEbpbJ1fSpP746Dcqi25xob +PodFGkGWGvhvPEUkf32DyQP/I1R82xSEuYDh0DC5xDCavpaPBhJmBGAoU7cfDLEx +CXH1rs//X1ZqdhPjG4Hsbns5NCaBC84sz0jVycVUT4wSXOlEBXTyqc03Y63QGXlU +4/X8/PdaFeIImqWpe8oKaviAEUIchkTPI6RrGUtYAWtX1f5tOSolOPGNyX4lyZ2L +TGbHuAfyndSAJ/lQad/EGUaKXLyXBD4nT1OAMIVKQ7VwVVH9Vg1zPvHPEZR+BqFj +VViey+gQZCQWZWyjmHm0c67oMQt3LY0pZ2N3d9Tv0QKBgQD+B6JwcY91FMjeXwQF +RlqhjFeLr/nXDc4T37fqTTHWr1jXLG7o6HpFQrToa8uFhJkALyXusurDFV4DCUFv +krB5toMdHx/dmXYGTTjW8PUrqznjeD4+je4XQvO95Cp+VpMlt6abQ5bGJtRdUs6g +k+UmiMX7cveAGTQ8M7YeK3fjMQKBgQDUWGBN2zmYG1csBd4Ylxoebz7wulyXJRm6 +1veMOb6jBrmWN/oZRDso6oATqImuv2g2vj4Em0lrAwkaj0HS4ofjjFP3DpYRSwzO +xfFby/om0WQ0cBfY9awUnWG32gnfiOgFGEpdC3WmMYDFetaRiKu5HfmdwBcEAtMt +rKkipTyxfQKBgQDU6m06NdR526voxlbGXQuFr+2IxTxxBb8eZTrvhTgqqtmZsEJd +sM0a1ChxTjhNdrAOuXXftdKTJIuhm9Zev+JugY0vkXDR+dg0u/DSJzA3I9LnV1dE +cw2GLbXCCUWcks/Oozlflaz/9He2qLtLV+qO+8CFWv0bPwTLGMSiUOixYQKBgF24 +J8EVGcVdg8rlSBH4VsnJ9bCPwB/hewqwqA9WySHw7OY1DIgsSiQT47VJdIMQ7bED +pCGqW+wEKfdz9OxbmPhATirDYE5/nkaArLcEPwL09dIDCzNxsqJil+dqL2NebHEb +OG76iNFyFdCTF7Kh7JDGfw414rKdgJEvHHMzFKeNAoGAfhWp5j2XxZy3Tv5hsA/I +DPWz8T6Sgw4joSQtq5TL/Hh7/6/SiH3bvmkvduOBEBFMXRqOpt24tEtPGfoDXAWf +w12ynnOD3o1bUuDR6k7Sj31gO5PtMarIhxecTBRuegbDlspXDSZfKIplmy29hsp2 +1X6qkVHc3N8m6VoiytdSyLw= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIICoDCCAYgCAhACMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCEludGVybTIu -MB4XDTIwMTEyNjIyMzEzNFoXDTIxMTEyNjIyMzEzNFowGDEWMBQGA1UEAwwNMS5l -eGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOjMVbBF -BjXahor6hl8ubJil8EDHvH+BKhuqkM4gJJbh7+vbwEkcO0WXRoXBRfxASiNdaUWF -dCEftpVpwcJ5JjAjgYRvVITQm1GjaKE5nsRB8fXm7+pE7K1Xwc6esgcMHs4bGmYt -q/YgPWLFETWE6nUDNNWoqclli8ByJoMIYeL5A2+jv+nhoZKbBIP5+289tNDVsM75 -QbInXtuZuWdIPf8AK70lg1+8bMPOowGuEZKWVLuK08ljaiM1nRvWLJBNyJKaVMxu -fwuHRcl1ZuQtJZ5PuPTBbvu53uzSmtQIhxtPdcIgXGEL6WSlU4WdGzBdf/I9zvzr -h2j/jA3nEYGyaTcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHpx2VYWmj6WvKexh -Z/zzdIXgFb2G6jT4NGSCk+ZObob581BqmDnUxBht4mui8zQS4QzX7N+DvAzMhT+/ -SbsDucd70OeEL/M27kQlZTy4kWTZKp0q5OSvRa0NQLXcS1DcIzxzr9NUg55p5X2+ -wdl9iB0Uo/q7MGKKaM5MyIgPAELnsfedsjE6QFz9xvAaMfawkolDuYQsvJciZpsv -XXAr+cFX8Y17qaPJMu7sOnOLt/VX2V3eaqw15fEwmWcfbNVBSGDpWUdeXNXoBI38 -b5Z6oSvB5aYLz0o2HD7407PphBPH3cVqCuby9XPtZiMhrHJYcos5ARjkjaEuoWUp -sip38w== +MIIDBjCCAe6gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 +ZXJtMi4wHhcNMjMxMjEyMTI0ODUzWhcNMjQxMjExMTI0ODUzWjAYMRYwFAYDVQQD +DA0xLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +0rYEtRNxi0Zve2RteH3LgIR1CanLhOsW0fFaMqUtAE5g9uE7ZWW3qrKhi7gjf54t +xzIT/AxF8oTYr11xU/Anm9EdDgxvNLxFHO+LfIC/4HuFpNSzVrfoGUHTNljSfAJ7 +5paFD75N/sqLv3wlwaBvxVtP+8IlSJWUi0Uc8fPOvQD4s1OIeESOpJgKKhqLEUCD +/6JxhliKBksCaO2UYhc1ULmFr6RDh0ntApJL3vLnu7rx6Ri6Qnh1eLYgvRIZSVIP +RNY7i6uI54dD2Tg9gNf2m3y6cvVPBqlZtAzFZBdDIrCE4DTBOrvk3FbLug6rC+y9 +faZxNIFg4jR0FMPS8hrP7QIDAQABo18wXTAdBgNVHQ4EFgQUcUjcqhYUEMGUIjIO +aMq5fgH8CQMwPAYDVR0jBDUwM4AUv0NLKQCR3Xh6AMJK2WhreTrXwa2hF6QVMBMx +ETAPBgNVBAMMCEludGVybTEuggIQATANBgkqhkiG9w0BAQsFAAOCAQEAJqfYYRYG +Mg588gBMiyc3kRUuYOO1+rNqIJXXFVKxJQ2MLT5t4v82J9vX9bfrGg31o3pDCqHM +HUkuIG+4N8YNNPNMOXrNb07dQgfcIKU+CMaHDo8e7mzW0V2mC85ab7Jgsoq8Sl3N +K16YOf6Hl1zIzq5lMdNkTi1ug808QCzzACXv2I7TMxtufyzMUhfgGoynFnj0K2Dp +RnyDVfLk7DpP1HUlnbWLQzXyrDknuOImZchvCpAoTxKEi+K1GVzlaN83/WfsznA5 +lRrO1pTMHiWX4OvFxCaXJchjqGtmlP+SY2lNnZ9TGVVpwRG7F1G9oaZc5L/XdHcN +aQR1LwnihejSFA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIICsjCCAZqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 -ZXJtMS4wHhcNMjAxMTI2MjIzMTM0WhcNMjExMTI2MjIzMTM0WjATMREwDwYDVQQD -DAhJbnRlcm0yLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALB5/TrD -/GsjnP2jY8JGm2QWGj9wxZO7zdx3ipwJKcFi0+Ol+W8dc7QGsefpFoNJ91oG6Gc1 -7rThTLPpwsXETGBrmce2LFGi30Ryuy+YueFK9qq4+LWweM/JujP7H3aX3hGevkE+ -Ru8p5XtFjDWeHs1v6CKratUW3iKf5o7h4OvwJqI45uYyIl5qfoL1CEgqTtxwAKiA -MzqLsz7Jt070rSzlLBvrDOESvzIOaIGEKJoTLBbAXGzeVifhYY/95pVwgU5/xscs -F1hAXBTtLIw/aInqAF3hLTXW4WIzhi3iKltzDwZG7YwKuQeNV4l/6dxYKfH/79ue -5KAQb2YnlBBWRusCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsF -AAOCAQEAq9pubtiro1qWNqfKn9Hf01dLdr344lbDrpzdhc/MI1M5neMalsygoG46 -IriLJ3Dv/2VSYonVsLAlfOrgiAzGzOP1XpSe5Xb1JAm9l0Oc/iwo3p9n7IwPxarT -O+lKpI6c8o308jdutdMfgGfuUL1rLnPVcnbNLDc3PZVzWxWrvS7rdQqUe2aA6k37 -2NrRK4R80CE9UXrzLz/G2z3IuwdJq3rvwJC9OE/bpG2nEpGyihcDl8SGEO0s8AlU -VVVlc6L3Q9NQLKajMk4mNs2DPdaxdQ/AYJ4Yz6iYhD1lnEuWYZ5hDkbznfW3PQyn -eV4ubLxGZp6ILdz4jeqeK9SQZdYCvg== +MIIDETCCAfmgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHUm9v +dC1jYTAeFw0yMzEyMTIxMjQ4NTNaFw0yNDEyMTExMjQ4NTNaMBMxETAPBgNVBAMM +CEludGVybTEuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvB5DipKu +gd5NnqADoTc4WEoV3KQUOqgZmJP9QVL+KTjsKU9xmZi8fH6SqZiauke83PeSPh3F +8IsJ7xRO4nuX0kdKjlLtk+NLEEWRvpyyujKvBg8uvueuiwwVNKk0OQdLU5wKKrPg +N1c3JE3UNYSdkCfxsYOkQ5fBhNliORd2TvPlDpfVU5Po4WHOHInCiXNRGQZvUmvG +NiHdT1/G7XLVhyCtSB3xHvhUZvIQ/iyyzqKHYe7tiXg/agFV9wWD4LcfUdppsqkr +MxrMBGbO08D2m9dlrNulSox5gYdbEkOU8BwBAUB39PFJndSlAl8jq02aLfQvgm04 +qp8Sa1lO+iDfJQIDAQABo3AwbjAdBgNVHQ4EFgQUwD6viy8ijJuZ536ogAryjqt8 +jCowTQYDVR0jBEYwRIAUCtII33+Z/yDKfh4Q0MKK5ez94W2hFqQUMBIxEDAOBgNV +BAMMB1Jvb3QtY2GCFHDmRS7viAZ+qCvMmiBh1Z0tDXHsMA0GCSqGSIb3DQEBCwUA +A4IBAQCn4uxqWqpswSTGW7LWI4FQCrQfv30eTLiEcARwxySRyKsMAqW94ZXnnCm/ +ZKZ4KX9oPjWeIIMunbjSP+3UtoFrQP/rRfVod1XjtMk1F1yA3MsEE0iedvWNg3gG +mC3v7kT5HeYBkSdyLNvkyRpYAcJELNKdX/ZujiIBeuduY2KKNwrRLUX7R1saBAVj +3F75g4IwtRewpooTvmpijARBSCPTicWYYZ8AD+wniIt1vLYqXqTBhzxzm8whYiE1 +0fdp7D3C/tjdME/VZjNFLhO2Ofdu1FLLSy4vL46mu8w/+x73tSPFoEkJ6tuo4j4z +WzYYmIREK4cwQYopt5tzkzsWvSQ5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIICsTCCAZmgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHUm9v -dC1jYTAeFw0yMDExMjYyMjMxMzNaFw0yMTExMjYyMjMxMzNaMBMxETAPBgNVBAMM -CEludGVybTEuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw71DNSsq -1hFqYqa6XrY/uFNiqXc6LdX07/zwuj2sFN/eeA8sUKbt5jG1KFRSHwgSprnA5w5T -PElivjTBz93Bk9a3J5uvCutYeNilX88h1fXT9W4kSeaXWV+0lp+GnsjlvPaa/1cr -8P+5lXvMGP1uU535UR4EZalCRnA5JxvTN4csxhwYyDxrMbu6UaJEbYBA7bA7WAFh -CU384MYo17FQgnL3IFeTknW7nsQ17F/mePFgAOw9id7RoWOmPjF0PFlGvLjSmYmx -rasv0yrSnE+F8XS+5kz2KigYTWWcgKFTUIZAc3mZlLkm45Q3M8I3+oa1Vem752ze -XVos08+svrV3JwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA -A4IBAQAbj+0u+5WCNg4VXIqurrCgidBOw3hY6sjpF1sZUhn4S09WJYYXsOWXfjM3 -hXpy568+/bi9mo8kiFS+oA76tX5Tj3oWzRPfqVPqGVi0BV+VSeoDlXLImrJ8SJ0v -N9BufvITM7RURCliPhNSRI4Iojs9Jk975ozqbud9DmcvcdC5909HtSQ/y34G3dxJ -yyNLZ8wt5p5giM9zMI1J6cctDjOaHb4zPqZ9BdUATDUAo6tlG3DUP1U6T2jMIwtY -du3TO3S7283U/a3pLAGbiN2XEDvdDBhqgEx4FIk+RBl2BFZV9oITFaZ3DNOnR3mE -Vd4Dkn3NTMHKpfXccjTlA3/nZUcC +MIIDADCCAeigAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwISW50 +ZXJtMS4wHhcNMjMxMjEyMTI0ODUzWhcNMjQxMjExMTI0ODUzWjATMREwDwYDVQQD +DAhJbnRlcm0yLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL+P3EUS +WLKC5AD95f1LDcIu4W96m+0ROq53xzxq4F30X+ivcGzfN05Hydu1VphvuOwMpyxW +RfLmlXLyigqnAwMMCCFUMf1HbETijRn0yOlNPlSDQba37TgK8AqQtNMA2qfx2rrw +WczYuIq4vwXhPH1u2qWjjBzy/ykxvn+s1PpZ/FPBXA8eawhHJbYLOTSghZQ98uVB +SSkKCP/LQKzhnPyB6B0+0h6EVGuTLou/PBBU5bufAOBJiufbhILRpEWeollx6gIC ++/T3pSxrMM2jc/jLo577CIlbcL5Hmu4NBMhaOLA1ffl4LWvxUxQuzPFqitNm9KP4 +5o3YyXMODVt3CtECAwEAAaNeMFwwHQYDVR0OBBYEFL9DSykAkd14egDCStloa3k6 +18GtMDsGA1UdIwQ0MDKAFMA+r4svIoybmed+qIAK8o6rfIwqoRakFDASMRAwDgYD +VQQDDAdSb290LWNhggIQADANBgkqhkiG9w0BAQsFAAOCAQEAfAjeG2/y6bVHVUi0 +j7wtn6VXiOPY7RTEXqFqU7GI//zUVFXntxaUxmlAoj5YRGwymLXDHULKLGVbo8RO +iHqzUDGDBztZpDyvt+5sPysaarvlS9D2x9Fw283uCuNuukv0Y9EoEufRvvleEXS6 +i4zLrH9cF7rlOpBkdBQRXQ+EMBiQYQtr/QIfHZ4dMUmf6KccW58HehBO3CfuFYem +y6cpNYlZAGkYWkn1ULhkNX4xhMiKjALUKPCwiRy9wOWQL09Af2gNEaXXiHdmYYq0 +WfIy55WwoGayIxRXywIK1VPI2mwK1EGF4+0qLatS0jgXpD9Jo2i0ZdZI57/KvmHd +5vpkpw== -----END CERTIFICATE-----