Skip to content

Commit f9fc94d

Browse files
authored
Merge pull request #6601 from bowen5/bowan/support-pem-cert-format
chore: support PEM format cert for service principal + cert auth
2 parents b03c9dd + 047a237 commit f9fc94d

File tree

4 files changed

+257
-12
lines changed

4 files changed

+257
-12
lines changed

pkg/provider/config/azure_auth.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package config
1818

1919
import (
20+
"crypto/rsa"
21+
"crypto/x509"
2022
"errors"
2123
"fmt"
2224
"io"
@@ -27,6 +29,7 @@ import (
2729
"sigs.k8s.io/yaml"
2830

2931
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
32+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
3033
"github.com/Azure/go-autorest/autorest/adal"
3134
"github.com/Azure/go-autorest/autorest/azure"
3235

@@ -151,7 +154,7 @@ func GetServicePrincipalToken(config *AzureAuthConfig, env *azure.Environment, r
151154
if err != nil {
152155
return nil, fmt.Errorf("reading the client certificate from file %s: %w", config.AADClientCertPath, err)
153156
}
154-
certificate, privateKey, err := adal.DecodePfxCertificateData(certData, config.AADClientCertPassword)
157+
certificate, privateKey, err := parseCertificate(certData, config.AADClientCertPassword)
155158
if err != nil {
156159
return nil, fmt.Errorf("decoding the client certificate: %w", err)
157160
}
@@ -205,7 +208,7 @@ func GetMultiTenantServicePrincipalToken(config *AzureAuthConfig, env *azure.Env
205208
if err != nil {
206209
return nil, fmt.Errorf("reading the client certificate from file %s: %w", config.AADClientCertPath, err)
207210
}
208-
certificate, privateKey, err := adal.DecodePfxCertificateData(certData, config.AADClientCertPassword)
211+
certificate, privateKey, err := parseCertificate(certData, config.AADClientCertPassword)
209212
if err != nil {
210213
return nil, fmt.Errorf("decoding the client certificate: %w", err)
211214
}
@@ -266,7 +269,7 @@ func GetNetworkResourceServicePrincipalToken(config *AzureAuthConfig, env *azure
266269
if err != nil {
267270
return nil, fmt.Errorf("reading the client certificate from file %s: %w", config.AADClientCertPath, err)
268271
}
269-
certificate, privateKey, err := adal.DecodePfxCertificateData(certData, config.AADClientCertPassword)
272+
certificate, privateKey, err := parseCertificate(certData, config.AADClientCertPassword)
270273
if err != nil {
271274
return nil, fmt.Errorf("decoding the client certificate: %w", err)
272275
}
@@ -383,3 +386,32 @@ func (config *AzureAuthConfig) ValidateForMultiTenant() error {
383386

384387
return nil
385388
}
389+
390+
// parseCertificate extracts the x509 certificate and RSA private key from the provided PFX or PEM data.
391+
// The cert data must contain a private key along with a certificate whose public key matches that of the
392+
// private key or an error is returned.
393+
func parseCertificate(certData []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
394+
certificates, privateKey, err := azidentity.ParseCertificates(certData, []byte(password))
395+
if err != nil {
396+
return nil, nil, err
397+
}
398+
399+
rsaPrivateKey, ok := privateKey.(*rsa.PrivateKey)
400+
if !ok {
401+
return nil, nil, fmt.Errorf("failed to parse certificate: private key is not RSA")
402+
}
403+
404+
// find the certificate with the matching public key of private key
405+
for _, cert := range certificates {
406+
certKey, ok := cert.PublicKey.(*rsa.PublicKey)
407+
if !ok {
408+
continue
409+
}
410+
if rsaPrivateKey.E == certKey.E && rsaPrivateKey.N.Cmp(certKey.N) == 0 {
411+
// found a match
412+
return cert, rsaPrivateKey, nil
413+
}
414+
}
415+
416+
return nil, nil, fmt.Errorf("failed to parse certificate: cannot find public key for private key")
417+
}

pkg/provider/config/azure_auth_test.go

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package config
1818

1919
import (
20+
"crypto/rsa"
2021
"fmt"
2122
"net/http"
2223
"net/http/httptest"
@@ -25,6 +26,7 @@ import (
2526

2627
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
2728
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
29+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
2830
"github.com/Azure/go-autorest/autorest/adal"
2931
"github.com/Azure/go-autorest/autorest/azure"
3032
"github.com/stretchr/testify/assert"
@@ -311,14 +313,14 @@ func TestGetServicePrincipalToken(t *testing.T) {
311313
assert.NoError(t, err)
312314
pfxContent, err := os.ReadFile("./testdata/test.pfx")
313315
assert.NoError(t, err)
314-
certificate, privateKey, err := adal.DecodePfxCertificateData(pfxContent, "id")
316+
certificates, privateKey, err := azidentity.ParseCertificates(pfxContent, []byte("id"))
315317
assert.NoError(t, err)
316-
spt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, config.AADClientID, certificate, privateKey, env.ServiceManagementEndpoint)
318+
spt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, config.AADClientID, certificates[0], privateKey.(*rsa.PrivateKey), env.ServiceManagementEndpoint)
317319
assert.NoError(t, err)
318320
assert.Equal(t, token, spt)
319321
})
320322

321-
t.Run("setup with SP and certificate (no certificate password)", func(t *testing.T) {
323+
t.Run("setup with SP with certificate has no password", func(t *testing.T) {
322324
config := &AzureAuthConfig{
323325
ARMClientConfig: azclient.ARMClientConfig{
324326
TenantID: "TenantID",
@@ -336,12 +338,54 @@ func TestGetServicePrincipalToken(t *testing.T) {
336338
assert.NoError(t, err)
337339
pfxContent, err := os.ReadFile("./testdata/testnopassword.pfx")
338340
assert.NoError(t, err)
339-
certificate, privateKey, err := adal.DecodePfxCertificateData(pfxContent, "")
341+
certificates, privateKey, err := azidentity.ParseCertificates(pfxContent, nil)
340342
assert.NoError(t, err)
341-
spt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, config.AADClientID, certificate, privateKey, env.ServiceManagementEndpoint)
343+
spt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, config.AADClientID, certificates[0], privateKey.(*rsa.PrivateKey), env.ServiceManagementEndpoint)
342344
assert.NoError(t, err)
343345
assert.Equal(t, token, spt)
344346
})
347+
348+
t.Run("setup with SP with certificate has multi public key", func(t *testing.T) {
349+
config := &AzureAuthConfig{
350+
ARMClientConfig: azclient.ARMClientConfig{
351+
TenantID: "TenantID",
352+
},
353+
AzureAuthConfig: azclient.AzureAuthConfig{
354+
AADClientID: "AADClientID",
355+
AADClientCertPath: "./testdata/testmultipublickey.pem",
356+
},
357+
}
358+
env := &azure.PublicCloud
359+
token, err := GetServicePrincipalToken(config, env, "")
360+
assert.NoError(t, err)
361+
362+
oauthConfig, err := adal.NewOAuthConfigWithAPIVersion(env.ActiveDirectoryEndpoint, config.TenantID, nil)
363+
assert.NoError(t, err)
364+
pfxContent, err := os.ReadFile("./testdata/testmultipublickey.pem")
365+
assert.NoError(t, err)
366+
certificates, privateKey, err := azidentity.ParseCertificates(pfxContent, nil)
367+
assert.NoError(t, err)
368+
// expected public key is in second bag
369+
certificate := certificates[1]
370+
spt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, config.AADClientID, certificate, privateKey.(*rsa.PrivateKey), env.ServiceManagementEndpoint)
371+
assert.NoError(t, err)
372+
assert.Equal(t, token, spt)
373+
})
374+
375+
t.Run("setup with SP with certificate has no public key", func(t *testing.T) {
376+
config := &AzureAuthConfig{
377+
ARMClientConfig: azclient.ARMClientConfig{
378+
TenantID: "TenantID",
379+
},
380+
AzureAuthConfig: azclient.AzureAuthConfig{
381+
AADClientID: "AADClientID",
382+
AADClientCertPath: "./testdata/testnopublickey.pem",
383+
},
384+
}
385+
env := &azure.PublicCloud
386+
_, err := GetServicePrincipalToken(config, env, "")
387+
assert.Error(t, err)
388+
})
345389
}
346390

347391
func TestGetMultiTenantServicePrincipalToken(t *testing.T) {
@@ -393,14 +437,31 @@ func TestGetMultiTenantServicePrincipalToken(t *testing.T) {
393437

394438
pfxContent, err := os.ReadFile("./testdata/testnopassword.pfx")
395439
assert.NoError(t, err)
396-
certificate, privateKey, err := adal.DecodePfxCertificateData(pfxContent, "")
440+
certificates, privateKey, err := azidentity.ParseCertificates(pfxContent, nil)
397441
assert.NoError(t, err)
398-
spt, err := adal.NewMultiTenantServicePrincipalTokenFromCertificate(multiTenantOAuthConfig, config.AADClientID, certificate, privateKey, env.ServiceManagementEndpoint)
442+
spt, err := adal.NewMultiTenantServicePrincipalTokenFromCertificate(multiTenantOAuthConfig, config.AADClientID, certificates[0], privateKey.(*rsa.PrivateKey), env.ServiceManagementEndpoint)
399443
assert.NoError(t, err)
400444

401445
assert.Equal(t, multiTenantToken, spt)
402446
})
403447

448+
t.Run("setup with SP with certificate has no public key", func(t *testing.T) {
449+
config := &AzureAuthConfig{
450+
ARMClientConfig: azclient.ARMClientConfig{
451+
TenantID: "TenantID",
452+
NetworkResourceTenantID: "NetworkResourceTenantID",
453+
},
454+
AzureAuthConfig: azclient.AzureAuthConfig{
455+
AADClientID: "AADClientID",
456+
AADClientCertPath: "./testdata/testnopublickey.pem",
457+
},
458+
NetworkResourceSubscriptionID: "NetworkResourceSubscriptionID",
459+
}
460+
env := &azure.PublicCloud
461+
_, err := GetMultiTenantServicePrincipalToken(config, env, nil)
462+
assert.Error(t, err)
463+
})
464+
404465
t.Run("setup with MSI and auxiliary token provider", func(t *testing.T) {
405466
const (
406467
managedIdentityToken = "managed-identity-token"
@@ -493,14 +554,32 @@ func TestGetNetworkResourceServicePrincipalToken(t *testing.T) {
493554

494555
pfxContent, err := os.ReadFile("./testdata/testnopassword.pfx")
495556
assert.NoError(t, err)
496-
certificate, privateKey, err := adal.DecodePfxCertificateData(pfxContent, "")
557+
certificates, privateKey, err := azidentity.ParseCertificates(pfxContent, nil)
497558
assert.NoError(t, err)
498-
spt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, config.AADClientID, certificate, privateKey, env.ServiceManagementEndpoint)
559+
spt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, config.AADClientID, certificates[0], privateKey.(*rsa.PrivateKey), env.ServiceManagementEndpoint)
499560
assert.NoError(t, err)
500561

501562
assert.Equal(t, token, spt)
502563
})
503564

565+
t.Run("setup with SP with certificate has no public key", func(t *testing.T) {
566+
config := &AzureAuthConfig{
567+
ARMClientConfig: azclient.ARMClientConfig{
568+
TenantID: "TenantID",
569+
NetworkResourceTenantID: "NetworkResourceTenantID",
570+
},
571+
AzureAuthConfig: azclient.AzureAuthConfig{
572+
AADClientID: "AADClientID",
573+
AADClientCertPath: "./testdata/testnopublickey.pem",
574+
},
575+
NetworkResourceSubscriptionID: "NetworkResourceSubscriptionID",
576+
}
577+
env := &azure.PublicCloud
578+
579+
_, err := GetNetworkResourceServicePrincipalToken(config, env, nil)
580+
assert.Error(t, err)
581+
})
582+
504583
t.Run("setup with MSI and auxiliary token provider", func(t *testing.T) {
505584
const (
506585
managedIdentityToken = "managed-identity-token"
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
Bag Attributes
2+
localKeyID: 01 00 00 00
3+
friendlyName: ee6d848f-c5d6-48fe-8e93-f5dfc3b7c98f
4+
Microsoft CSP Name: Microsoft Enhanced RSA and AES Cryptographic Provider
5+
Key Attributes
6+
X509v3 Key Usage: 10
7+
-----BEGIN PRIVATE KEY-----
8+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDU+YW7Fw3hmCW8
9+
WelE5OpDysbVRSz4LnvijNhpMq4V7PhS6S4tzetpISjI62nfxy9vLsUOCmOUbsvV
10+
AqgGiJp/hMCA3MkJ25L0jVcV7XQejYp19e9qX+MgAfkFKMGv1AaOfevHdyrywK8Y
11+
n8M4WEUmFtqWlYU4ckP4HNwV4/BspOulsOVVrZD4K2MQApWIg5N05zB4ezgW4zev
12+
Kwo1RMIRSl592lUfoe2Cvatp44kyENoVY00uFDKpTWiAKGGgThPutIo/ckECotuN
13+
XT9QjD0WqJjZCTePvVVB4/Ojq6INV61qtuWRup7dgF7PrlQqbUyXaXARiNofSg2e
14+
9bo/fOHFAgMBAAECggEAU+0ol/uTyszMQhckZ7PV5XUpOa4S9JJM25ApT/tawuUp
15+
TnL5ca9uD3WzvsmWZUr3FFdX7BqH91xaEs0DLd/zEkFcIuvehXXzyU9RfCCg29Fn
16+
OOj7ue2jcV+VpETVXtas5sYUffwl/peT6J48rh2K0mG7LhAp+X597m5hBHdYrVbw
17+
JTz/tesztAYEUzNutRg2ejtIgkx80DQE6kgdNFMzVfYlaMQZag1u/QxZoiUvmZIe
18+
E2dErntm9jLn8Nz4bKIJTm09lH3c7Y9ywLuluGjL+SDa+u/rEaOOXqs+7E94/xey
19+
k/jDCWxgTXdr7PK5rd6X45EzcgoFOXeUiR471Gh+GQKBgQDg+DGEqyAayqZTO6RE
20+
gFDfrHFshwe9OAE+yjF1TbxRtFlI2TvdnVAc6h2nUNoqMecx2oHjMRQAwIieM2o5
21+
MO4daWIFvehBJ4J06aNbEEuHFW43unURCPLpZS7efGwv0ApmPcsYcHHfIZnzWXji
22+
Ml08lBQKb9htv9RSjXrxI7TQTwKBgQDyWcj/iNdQPY+a8wAb73ysbG9QoBlsgrAz
23+
UNAImUKKFZjFPmLuPUfVIZ9LqTxDrJ+AFtNMO8QNLXGabLs2CfcrMPEY+lunhYTA
24+
fA1o5j4CzrnA+azugWl1DwbnhUYYMFRWx/BuKqCn2LBNuHosFH0zk9O7SHZS1+iT
25+
q0tGiOozqwKBgQCQqwos5l6e2/JZU+Euq9VWAO5ve+XeKEWkuyFS7cpMQE2qKwf0
26+
W1VJQsQO9E9XEwA5bupXzxet5CH2mdmVLYHyJ/KA/r58J4wc4qHJzZDELWPTMnRV
27+
oAuVSxv4tspbdM07MkGIVcbkVhdKBh9WVkzex9qbW5EyAknnTFPi/bMowQKBgAs7
28+
+kNONpzznZqTNSgWW/MqO6bDJSqQjFZ0opAjeqAoDCLol3Fvycqpelbpi2+fqu0n
29+
Ibhg9N+fgaqk67C/mYOZCzQbNvB3EgZSOdTpB2rd5mJ5sHiF6zuP7MQCu5MXenFj
30+
Z1PUCgp90v5nVNKCSKOBcMk3vLRuacuenyiv5BttAoGBAJLvAzKf1Wff+BUm2hdn
31+
HLw1iqWCzCEyOcv3zajHDJuWxJ0hon+RZdwDhUBgdz9ivKCK4GNl5UbwRiDMzJme
32+
xaN3c4gktOPwoNW8NZsqQg9Rxqt31bjsd0DxeJvlAxyHAUutYedQmzYfnoXsrpcv
33+
tIzf8vsCXOWy4YMexNcU7akK
34+
-----END PRIVATE KEY-----
35+
-----BEGIN CERTIFICATE-----
36+
MIIDazCCAlOgAwIBAgIUNa/zzLTnGkYKtT0IK5ygLSSbXiUwDQYJKoZIhvcNAQEL
37+
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
38+
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA3MTUwNDAzNDZaFw0yNDA4
39+
MTQwNDAzNDZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
40+
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
41+
AQUAA4IBDwAwggEKAoIBAQDvMbJmVaWrBDrUNiImXK9gjJn1e5y+Jd50d0cbBmys
42+
PBTIrU+pxsV3Cvo9FlG3C7YTOGirqIOZV1l15XAGzh/LusgXbZ08zBVo4OOwza+a
43+
vY77VRd0n4QHGYCAi9ML5Hb62lSsV1Ku4cQ+7nkdLGM4l4bWtZrfE3OENYfb5GKT
44+
lU435zZL2Ru1inC3MkCvXQTOy9F1+kVEMVyGMHFkS4K8LGGzqbEedl/mjWT8wf9f
45+
0jD9BYvdk8T43ZeUhnvVuWE74ghRIU1Wwvcr4IdbCJecw660bsM84OomPetlnr04
46+
lSyFKF7NtZ1exluhrXztlW+FN2uc5/tUlVGolX3jwaDFAgMBAAGjUzBRMB0GA1Ud
47+
DgQWBBTk6/C14Dpyycu/dm7ZY0nmyulSJzAfBgNVHSMEGDAWgBTk6/C14Dpyycu/
48+
dm7ZY0nmyulSJzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCa
49+
KsoDZKvp3D4z5NFo/iN6xCqPEfR7Qttl6SVY46CsXnXAac8Nj023wRNzmE4C8jRY
50+
4QUbKMmtrs9wVVdGQZsF1pmuWTDm8ftQB+tfVeZF2vMmIxp7lcGldHTZmp+x1oQW
51+
CFa5I06dflJDsc9TmNx/suHo8gIf0fyWANckeSu999noI3oQ7SBFa97Yf3qPHAOu
52+
RVWzzeCAg/785sJuGLSKFqQo5nVjaEQttho5pFmL/4CHKj1O4nDNgvs9C0h5efKS
53+
bj+YzaeQsOdmI09DXA1ygK1g010XQOph5zIfJ9Unbz9DOIj532xIKFFjB/mkNMtc
54+
nuyjElifsXaWcDct1X2e
55+
-----END CERTIFICATE-----
56+
Bag Attributes
57+
localKeyID: 01 00 00 00
58+
subject=CN = testnopassword
59+
issuer=CN = testnopassword
60+
-----BEGIN CERTIFICATE-----
61+
MIIDODCCAiCgAwIBAgIQbWgyemT/RBiXekVb2KgmiTANBgkqhkiG9w0BAQsFADAZ
62+
MRcwFQYDVQQDEw50ZXN0bm9wYXNzd29yZDAeFw0yNDAzMDYwNzIwNDZaFw0zNDAz
63+
MDYwNzMwNDZaMBkxFzAVBgNVBAMTDnRlc3Rub3Bhc3N3b3JkMIIBIjANBgkqhkiG
64+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1PmFuxcN4ZglvFnpROTqQ8rG1UUs+C574ozY
65+
aTKuFez4UukuLc3raSEoyOtp38cvby7FDgpjlG7L1QKoBoiaf4TAgNzJCduS9I1X
66+
Fe10Ho2KdfXval/jIAH5BSjBr9QGjn3rx3cq8sCvGJ/DOFhFJhbalpWFOHJD+Bzc
67+
FePwbKTrpbDlVa2Q+CtjEAKViIOTdOcweHs4FuM3rysKNUTCEUpefdpVH6Htgr2r
68+
aeOJMhDaFWNNLhQyqU1ogChhoE4T7rSKP3JBAqLbjV0/UIw9FqiY2Qk3j71VQePz
69+
o6uiDVetarblkbqe3YBez65UKm1Ml2lwEYjaH0oNnvW6P3zhxQIDAQABo3wwejAO
70+
BgNVHQ8BAf8EBAMCBaAwCQYDVR0TBAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
71+
KwYBBQUHAwIwHwYDVR0jBBgwFoAU3F9FjkPnojeuty3srItMsgH2vXAwHQYDVR0O
72+
BBYEFNxfRY5D56I3rrct7KyLTLIB9r1wMA0GCSqGSIb3DQEBCwUAA4IBAQBIXb7O
73+
2dbGJLbqOVSQ0D7WWNl8VmzC7H5wtwiN50b6rKNTyxy3M3WYL7tDPgUDBSgqYpBG
74+
aKMAM86aX8o4pWdXKy3pl8DJsl+rRUQEFaKWXV30x2V4gcP2Ldtxr9oXxO0LdkGn
75+
BWC4QplbFGSns545rDMcpDPRP7O23ZezJA+qUU/6YwdwqOvCH3iE5jq0JQ0bFPO7
76+
yHDL4Zm2BIy+E50P+9uieoXnq7Kv2ksn/eTxZvYxVZYDrSbOE0QApB4imIxmLjSg
77+
mxlOuLnsmi/Okpzub3l1D1ZcAwVRZqb8df7Gpr3F2GPPduYPoIOqZbapjyLd7K8x
78+
+zU65sJkBX29hbY+
79+
-----END CERTIFICATE-----
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
Bag Attributes
2+
localKeyID: 01 00 00 00
3+
friendlyName: ee6d848f-c5d6-48fe-8e93-f5dfc3b7c98f
4+
Microsoft CSP Name: Microsoft Enhanced RSA and AES Cryptographic Provider
5+
Key Attributes
6+
X509v3 Key Usage: 10
7+
-----BEGIN PRIVATE KEY-----
8+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDU+YW7Fw3hmCW8
9+
WelE5OpDysbVRSz4LnvijNhpMq4V7PhS6S4tzetpISjI62nfxy9vLsUOCmOUbsvV
10+
AqgGiJp/hMCA3MkJ25L0jVcV7XQejYp19e9qX+MgAfkFKMGv1AaOfevHdyrywK8Y
11+
n8M4WEUmFtqWlYU4ckP4HNwV4/BspOulsOVVrZD4K2MQApWIg5N05zB4ezgW4zev
12+
Kwo1RMIRSl592lUfoe2Cvatp44kyENoVY00uFDKpTWiAKGGgThPutIo/ckECotuN
13+
XT9QjD0WqJjZCTePvVVB4/Ojq6INV61qtuWRup7dgF7PrlQqbUyXaXARiNofSg2e
14+
9bo/fOHFAgMBAAECggEAU+0ol/uTyszMQhckZ7PV5XUpOa4S9JJM25ApT/tawuUp
15+
TnL5ca9uD3WzvsmWZUr3FFdX7BqH91xaEs0DLd/zEkFcIuvehXXzyU9RfCCg29Fn
16+
OOj7ue2jcV+VpETVXtas5sYUffwl/peT6J48rh2K0mG7LhAp+X597m5hBHdYrVbw
17+
JTz/tesztAYEUzNutRg2ejtIgkx80DQE6kgdNFMzVfYlaMQZag1u/QxZoiUvmZIe
18+
E2dErntm9jLn8Nz4bKIJTm09lH3c7Y9ywLuluGjL+SDa+u/rEaOOXqs+7E94/xey
19+
k/jDCWxgTXdr7PK5rd6X45EzcgoFOXeUiR471Gh+GQKBgQDg+DGEqyAayqZTO6RE
20+
gFDfrHFshwe9OAE+yjF1TbxRtFlI2TvdnVAc6h2nUNoqMecx2oHjMRQAwIieM2o5
21+
MO4daWIFvehBJ4J06aNbEEuHFW43unURCPLpZS7efGwv0ApmPcsYcHHfIZnzWXji
22+
Ml08lBQKb9htv9RSjXrxI7TQTwKBgQDyWcj/iNdQPY+a8wAb73ysbG9QoBlsgrAz
23+
UNAImUKKFZjFPmLuPUfVIZ9LqTxDrJ+AFtNMO8QNLXGabLs2CfcrMPEY+lunhYTA
24+
fA1o5j4CzrnA+azugWl1DwbnhUYYMFRWx/BuKqCn2LBNuHosFH0zk9O7SHZS1+iT
25+
q0tGiOozqwKBgQCQqwos5l6e2/JZU+Euq9VWAO5ve+XeKEWkuyFS7cpMQE2qKwf0
26+
W1VJQsQO9E9XEwA5bupXzxet5CH2mdmVLYHyJ/KA/r58J4wc4qHJzZDELWPTMnRV
27+
oAuVSxv4tspbdM07MkGIVcbkVhdKBh9WVkzex9qbW5EyAknnTFPi/bMowQKBgAs7
28+
+kNONpzznZqTNSgWW/MqO6bDJSqQjFZ0opAjeqAoDCLol3Fvycqpelbpi2+fqu0n
29+
Ibhg9N+fgaqk67C/mYOZCzQbNvB3EgZSOdTpB2rd5mJ5sHiF6zuP7MQCu5MXenFj
30+
Z1PUCgp90v5nVNKCSKOBcMk3vLRuacuenyiv5BttAoGBAJLvAzKf1Wff+BUm2hdn
31+
HLw1iqWCzCEyOcv3zajHDJuWxJ0hon+RZdwDhUBgdz9ivKCK4GNl5UbwRiDMzJme
32+
xaN3c4gktOPwoNW8NZsqQg9Rxqt31bjsd0DxeJvlAxyHAUutYedQmzYfnoXsrpcv
33+
tIzf8vsCXOWy4YMexNcU7akK
34+
-----END PRIVATE KEY-----
35+
-----BEGIN CERTIFICATE-----
36+
MIIDazCCAlOgAwIBAgIUNa/zzLTnGkYKtT0IK5ygLSSbXiUwDQYJKoZIhvcNAQEL
37+
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
38+
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA3MTUwNDAzNDZaFw0yNDA4
39+
MTQwNDAzNDZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
40+
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
41+
AQUAA4IBDwAwggEKAoIBAQDvMbJmVaWrBDrUNiImXK9gjJn1e5y+Jd50d0cbBmys
42+
PBTIrU+pxsV3Cvo9FlG3C7YTOGirqIOZV1l15XAGzh/LusgXbZ08zBVo4OOwza+a
43+
vY77VRd0n4QHGYCAi9ML5Hb62lSsV1Ku4cQ+7nkdLGM4l4bWtZrfE3OENYfb5GKT
44+
lU435zZL2Ru1inC3MkCvXQTOy9F1+kVEMVyGMHFkS4K8LGGzqbEedl/mjWT8wf9f
45+
0jD9BYvdk8T43ZeUhnvVuWE74ghRIU1Wwvcr4IdbCJecw660bsM84OomPetlnr04
46+
lSyFKF7NtZ1exluhrXztlW+FN2uc5/tUlVGolX3jwaDFAgMBAAGjUzBRMB0GA1Ud
47+
DgQWBBTk6/C14Dpyycu/dm7ZY0nmyulSJzAfBgNVHSMEGDAWgBTk6/C14Dpyycu/
48+
dm7ZY0nmyulSJzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCa
49+
KsoDZKvp3D4z5NFo/iN6xCqPEfR7Qttl6SVY46CsXnXAac8Nj023wRNzmE4C8jRY
50+
4QUbKMmtrs9wVVdGQZsF1pmuWTDm8ftQB+tfVeZF2vMmIxp7lcGldHTZmp+x1oQW
51+
CFa5I06dflJDsc9TmNx/suHo8gIf0fyWANckeSu999noI3oQ7SBFa97Yf3qPHAOu
52+
RVWzzeCAg/785sJuGLSKFqQo5nVjaEQttho5pFmL/4CHKj1O4nDNgvs9C0h5efKS
53+
bj+YzaeQsOdmI09DXA1ygK1g010XQOph5zIfJ9Unbz9DOIj532xIKFFjB/mkNMtc
54+
nuyjElifsXaWcDct1X2e
55+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)