Skip to content

Commit

Permalink
Fix race condition on verification with multiple signatures attached …
Browse files Browse the repository at this point in the history
…to image (sigstore#3486)

Fixes sigstore#3476

Signed-off-by: Mukuls77 <mukul.sharma77@gmail.com>
  • Loading branch information
Mukuls77 committed Jan 25, 2024
1 parent 9bc3ee3 commit f43eb6b
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 22 deletions.
31 changes: 21 additions & 10 deletions pkg/cosign/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,17 @@ func verifyOCISignature(ctx context.Context, verifier signature.Verifier, sig pa
return verifier.VerifySignature(bytes.NewReader(signature), bytes.NewReader(payload), options.WithContext(ctx))
}

// ValidateAndUnpackCert creates a Verifier from a certificate. Veries that the certificate
// chains up to a trusted root. Optionally verifies the subject and issuer of the certificate.
// ValidateAndUnpackCert creates a Verifier from a certificate. Verifies that the
// certificate chains up to a trusted root using intermediate certificate chain coming from CheckOpts.
// Optionally verifies the subject and issuer of the certificate.
func ValidateAndUnpackCert(cert *x509.Certificate, co *CheckOpts) (signature.Verifier, error) {
return ValidateAndUnpackCertWithIntermediates(cert, co, co.IntermediateCerts)
}

// ValidateAndUnpackCertWithIntermediates creates a Verifier from a certificate. Verifies that the
// certificate chains up to a trusted root using intermediate cert passed as separate argument.
// Optionally verifies the subject and issuer of the certificate.
func ValidateAndUnpackCertWithIntermediates(cert *x509.Certificate, co *CheckOpts, intermediateCerts *x509.CertPool) (signature.Verifier, error) {
verifier, err := signature.LoadVerifier(cert.PublicKey, crypto.SHA256)
if err != nil {
return nil, fmt.Errorf("invalid certificate found on signature: %w", err)
Expand All @@ -239,7 +247,8 @@ func ValidateAndUnpackCert(cert *x509.Certificate, co *CheckOpts) (signature.Ver
}

// Now verify the cert, then the signature.
chains, err := TrustedCert(cert, co.RootCerts, co.IntermediateCerts)
chains, err := TrustedCert(cert, co.RootCerts, intermediateCerts)

if err != nil {
return nil, err
}
Expand Down Expand Up @@ -721,19 +730,21 @@ func verifyInternal(ctx context.Context, sig oci.Signature, h v1.Hash,
return false, err
}
// If there is no chain annotation present, we preserve the pools set in the CheckOpts.
if len(chain) > 0 {
if len(chain) == 1 {
co.IntermediateCerts = nil
} else if co.IntermediateCerts == nil {
var pool *x509.CertPool
if len(chain) > 1 {
if co.IntermediateCerts == nil {
// If the intermediate certs have not been loaded in by TUF
pool := x509.NewCertPool()
pool = x509.NewCertPool()
for _, cert := range chain[:len(chain)-1] {
pool.AddCert(cert)
}
co.IntermediateCerts = pool
}
}
verifier, err = ValidateAndUnpackCert(cert, co)
// In case pool is not set than set it from co.IntermediateCerts
if pool == nil {
pool = co.IntermediateCerts
}
verifier, err = ValidateAndUnpackCertWithIntermediates(cert, co, pool)
if err != nil {
return false, err
}
Expand Down
30 changes: 30 additions & 0 deletions pkg/cosign/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1228,6 +1228,36 @@ func TestValidateAndUnpackCertWithIdentities(t *testing.T) {
}
}
}

func TestValidateAndUnpackCertWithIntermediatesSuccess(t *testing.T) {
subject := "email@email"
oidcIssuer := "https://accounts.google.com"

rootCert, rootKey, _ := test.GenerateRootCa()
subCert, subKey, _ := test.GenerateSubordinateCa(rootCert, rootKey)
leafCert, _, _ := test.GenerateLeafCert(subject, oidcIssuer, subCert, subKey)

rootPool := x509.NewCertPool()
rootPool.AddCert(rootCert)
subPool := x509.NewCertPool()
rootPool.AddCert(subCert)

co := &CheckOpts{
RootCerts: rootPool,
IgnoreSCT: true,
Identities: []Identity{{Subject: subject, Issuer: oidcIssuer}},
}

_, err := ValidateAndUnpackCertWithIntermediates(leafCert, co, subPool)
if err != nil {
t.Errorf("ValidateAndUnpackCertWithIntermediates expected no error, got err = %v", err)
}
err = CheckCertificatePolicy(leafCert, co)
if err != nil {
t.Errorf("CheckCertificatePolicy expected no error, got err = %v", err)
}
}

func TestCompareSigs(t *testing.T) {
// TODO(nsmith5): Add test cases for invalid signature, missing signature etc
tests := []struct {
Expand Down
43 changes: 31 additions & 12 deletions test/e2e_test_attach.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# This test case test two scenarios
# scenario 1: Attach a single signature with certificate and certificate chain to an artifact
# and verify it using root certificate
# scenario 2: Attaches second signature with diffrent certificate and certificate chain to same
# artifact and verify it using both root certificates separately

set -ex

go build -o cosign ./cmd/cosign
Expand All @@ -25,6 +31,10 @@ cp ./test/testdata/test_attach_private_key $tmp/private_key
cp ./test/testdata/test_attach_leafcert.pem $tmp/leafcert.pem
cp ./test/testdata/test_attach_certchain.pem $tmp/certchain.pem
cp ./test/testdata/test_attach_rootcert.pem $tmp/rootcert.pem
cp ./test/testdata/test_attach_second_private_key $tmp/secondprivate_key
cp ./test/testdata/test_attach_second_leafcert.pem $tmp/secondleafcert.pem
cp ./test/testdata/test_attach_second_certchain.pem $tmp/secondcertchain.pem
cp ./test/testdata/test_attach_second_rootcert.pem $tmp/secondrootcert.pem

pushd $tmp

Expand All @@ -44,39 +54,48 @@ IMAGE_URI_DIGEST=$IMAGE_URI@$SRC_DIGEST
## Generate
./cosign generate $IMAGE_URI_DIGEST > payload.json

## Sign with Leafcert Private Key
## Scenario 1 Starts

## Sign with First Leafcert Private Key
openssl dgst -sha256 -sign ./private_key -out payload.sig payload.json
cat payload.sig | base64 > payloadbase64.sig


SIGNATURE=$(cat payloadbase64.sig | base64)
echo "Signature: $SIGNATURE"

PAYLOAD=$(cat payload.json)
echo "Payload: $PAYLOAD"



## Attach Signature, payload, cert and cert-chain
./cosign attach signature --signature ./payloadbase64.sig --payload ./payload.json --cert ./leafcert.pem --cert-chain ./certchain.pem $IMAGE_URI_DIGEST


## confirm manifest conatins annotation for cert and cert chain
crane manifest $(./cosign triangulate $IMAGE_URI_DIGEST) | grep -q "application/vnd.oci.image.config.v1+json"
crane manifest $(./cosign triangulate $IMAGE_URI_DIGEST) | grep -q "dev.sigstore.cosign/certificate"
crane manifest $(./cosign triangulate $IMAGE_URI_DIGEST) | grep -q "dev.sigstore.cosign/chain"

## Verify Signature, payload, cert and cert-chain using SIGSTORE_ROOT_FILE
## Verify Signature, payload, cert and cert-chain using Root certificate only
./cosign verify $IMAGE_URI_DIGEST --insecure-ignore-sct --insecure-ignore-tlog --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*' --cert-chain=./rootcert.pem

## Scenario 2 Starts

## Sign with Leafcert Private Key
openssl dgst -sha256 -sign ./secondprivate_key -out secondpayload.sig payload.json
cat secondpayload.sig | base64 > secondpayloadbase64.sig

SIGNATURE2=$(cat secondpayloadbase64.sig | base64)
echo "Second Signature: $SIGNATURE2"

## Attach Second Signature, payload, cert and cert-chain
./cosign attach signature --signature ./secondpayloadbase64.sig --payload ./payload.json --cert ./secondleafcert.pem --cert-chain ./secondcertchain.pem $IMAGE_URI_DIGEST

export SIGSTORE_ROOT_FILE=./rootcert.pem
./cosign verify $IMAGE_URI_DIGEST --insecure-ignore-sct --insecure-ignore-tlog --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*'
## Verify Signature, payload, cert and cert-chain using Root certificate only
./cosign verify $IMAGE_URI_DIGEST --insecure-ignore-sct --insecure-ignore-tlog --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*' --cert-chain=./rootcert.pem

./cosign verify $IMAGE_URI_DIGEST --insecure-ignore-sct --insecure-ignore-tlog --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*' --cert-chain=./secondrootcert.pem

# clean up a bit
for image in $IMAGE_URI_DIGEST
do
(crane delete $(./cosign triangulate $IMAGE_URI_DIGEST)) || true
done
./cosign clean $IMAGE_URI_DIGEST --force=true
crane delete $IMAGE_URI_DIGEST || true


Expand Down
95 changes: 95 additions & 0 deletions test/testdata/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,98 @@ $ cp certChain.crt test/testdata/test_attach_certchain.pem
```shell
$ cp leafCA.crt test/testdata/test_attach_leafcert.pem
```

16. Generate a private key for Second Root certificate

```shell
$ openssl genrsa -des3 -out secondrootCA.key 2048
```
17. Generate Second Root certificate

```shell
$ openssl req -x509 -new -nodes -key secondrootCA.key -sha256 -days 1825 -out secondrootCA.crt
```
in Certificate generation set following values
C = IN, ST = DEL, L = DEL, O = exampleclient.com, OU = sigstore, CN = sigstore, emailAddress = foo@exampleclient.com

18. Generate Private key for second Intermediate certificate

```shell
$ openssl genrsa -out secondintermediateCA.key 2048
```
19. Generate CSR for second Intermediate certificate

```shell
$ openssl req -new -key secondintermediateCA.key -out secondintermediateCA.csr
```
in Certificate generation set following values
C = IN, ST = DEL, L = DEL, O = exampleclient.com, OU = sigstore-sub, CN = sigstore-sub, emailAddress = foo@exampleclient.com

20. Create intermediate certificate config file by name "intermediateConfigFile" having content
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

21. Create intermediate certificate

```shell
$ openssl x509 -req -in secondintermediateCA.csr -CA secondrootCA.crt -CAkey secondrootCA.key -CAcreateserial -CAserial secondintermediateca.srl -out secondintermediateCA.crt -days 1825 -sha256 -extfile intermediateConfigFile
```

22. Create Private key for second leaf certificate

```shell
$ openssl genrsa -out secondleafCA.key 2048
```

23. Create CSR for second Leaf certificate

```shell
$ openssl req -new -key secondleafCA.key -out secondleafCA.csr
```
in certificate generation set following values
C = IN, ST = DEL, L = DEL, O = exampleclient.com, OU = sigstore-leaf, CN = sigstore-leaf, emailAddress = foo@exampleclient.com

24. Create Leaf certificate config file by name "leafConfigFile" having content
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage=codeSigning
subjectAltName=email:copy

25. Create Leaf certificate

```shell
$ openssl x509 -req -in secondleafCA.csr -CA secondintermediateCA.crt -CAkey secondintermediateCA.key -CAcreateserial -CAserial secondleafca.srl -out secondleafCA.crt -days 1825 -sha256 -extfile leafConfigFile
```

26. Generate Certificate chain by concatinating second Intermediate certificate and second Root certificate

```shell
$ cat secondintermediateCA.crt secondrootCA.crt > secondcertChain.crt
```

27. copy private key of second Leaf certificate to test/testdata/test_attach_second_private_key

```shell
$ cp secondleafCA.key test/testdata/test_attach_second_private_key
```

28. copy root certificate to test/testdata/test_attach_second_rootcert.pem

```shell
$ cp secondrootCA.crt test/testdata/test_attach_second_rootcert.pem
```

29. copy second cert chain to test/testdata/test_attach_second_certchain.pem

```shell
$ cp secondcertChain.crt test/testdata/test_attach_second_certchain.pem
```

30. copy second Leaf certificate to test/testdata/test_attach_second_leafcert.pem

```shell
$ cp secondleafCA.crt test/testdata/test_attach_second_leafcert.pem
```
49 changes: 49 additions & 0 deletions test/testdata/test_attach_second_certchain.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
-----BEGIN CERTIFICATE-----
MIIEIDCCAwigAwIBAgIUP2BVjdyg37MRM6Xa2l0TSF2/+rcwDQYJKoZIhvcNAQEL
BQAwgZExCzAJBgNVBAYTAklOMQwwCgYDVQQIDANERUwxDDAKBgNVBAcMA0RFTDEa
MBgGA1UECgwRZXhhbXBsZWNsaWVudC5jb20xETAPBgNVBAsMCHNpZ3N0b3JlMREw
DwYDVQQDDAhzaWdzdG9yZTEkMCIGCSqGSIb3DQEJARYVZm9vQGV4YW1wbGVjbGll
bnQuY29tMB4XDTI0MDExODEwMTE0N1oXDTI5MDExNjEwMTE0N1owgZkxCzAJBgNV
BAYTAklOMQwwCgYDVQQIDANERUwxDDAKBgNVBAcMA0RFTDEaMBgGA1UECgwRZXhh
bXBsZWNsaWVudC5jb20xFTATBgNVBAsMDHNpZ3N0b3JlLXN1YjEVMBMGA1UEAwwM
c2lnc3RvcmUtc3ViMSQwIgYJKoZIhvcNAQkBFhVmb29AZXhhbXBsZWNsaWVudC5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz37o+ObXK1b8/RqEv
MaQQp6X1aD1FptsW+X07ESqZz0XiJToGMdE2ETlFza9VyyeMwJF6YcFK3wfsakB0
QG40nMt7KI8cT/sFot8WzQTVTSe0HfALvdOnY4OBM5mZPmQlemWfpipsTIiCyIXp
I2tWSjR7rtDlw2VW5N+wpyn+qid+EZRm/ZGzQhwAcH0u+di+6ynt2rdcSn1RMsRr
vGB0/yqbboRsBh5pWNl/42mCoWFRFk3vsUvxKDieTDdTy53vqi7MNB3wDZ3TRj1w
StExZYMzXeRi2VxSzt0k1u/YGgHmQOjPmxHSbQ929V+fXjw3xR06z77ojDxCCQvH
cLJxAgMBAAGjZjBkMB0GA1UdDgQWBBShacFO3pe6fgps4IcgbDV5zS5cZTAfBgNV
HSMEGDAWgBS6b9p3peGUOXzfDnq3w7NAlKX+dDASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAHnds5GMnQOX8QddM
1fqpacdBOS2FhkyNGBmAramSNAEnfYPp7lZqn/TjCytUsiNPliiXpp+LF8a8pZvD
xjayyKiEbHitJdvsMf/kP8uxgv4SdiT96ycDwHCAt1obgG71ywoi9nbBAkuTep5n
+PYB8G0cwCAvyNQE0sOUXYqHHMRwAI5ke13nqWBxDBrx12iTpCL/910XUhpSVlXX
Al8zx2LT7scRu83pZBPFvr9j7IexlinhMH37xgAVXa6BPpATvvAXZg5gn1gtYAex
Af79/eiJn6zJXnF066dXW7OBpV/cILPkBciyC5Il8UMukEM5I36XH4NqPBd/JBPd
VRrmug==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEBTCCAu2gAwIBAgIUKv9OVy7IcTL6gvqPRcJZKIX0/ucwDQYJKoZIhvcNAQEL
BQAwgZExCzAJBgNVBAYTAklOMQwwCgYDVQQIDANERUwxDDAKBgNVBAcMA0RFTDEa
MBgGA1UECgwRZXhhbXBsZWNsaWVudC5jb20xETAPBgNVBAsMCHNpZ3N0b3JlMREw
DwYDVQQDDAhzaWdzdG9yZTEkMCIGCSqGSIb3DQEJARYVZm9vQGV4YW1wbGVjbGll
bnQuY29tMB4XDTI0MDExODEwMDkzM1oXDTI5MDExNjEwMDkzM1owgZExCzAJBgNV
BAYTAklOMQwwCgYDVQQIDANERUwxDDAKBgNVBAcMA0RFTDEaMBgGA1UECgwRZXhh
bXBsZWNsaWVudC5jb20xETAPBgNVBAsMCHNpZ3N0b3JlMREwDwYDVQQDDAhzaWdz
dG9yZTEkMCIGCSqGSIb3DQEJARYVZm9vQGV4YW1wbGVjbGllbnQuY29tMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn9FAPZNON2O7k/fYqpI894aUf3ur
LyJsEx6RhC7JYjumc4VLvDA9vSauXeM4fQ+YDaOs9K8FujDbAFGsrltXBBA/Czsd
Ml/OMkkn5ZzDkTXqFXVer31M0fNLWMoAZ9q7c601ndRuTLDp8Ka3aR2Caj2W7VgO
mGDUhgaVo31Omx4TM5ydnSLGewRfw/7nFveHBGKaRG+tVF1zLZwTESGG5/lV8Vq1
cSctqK9kDwfNFzZKjpIsEDoT2L3ZosevtC3lY07KqvtKEOS9QWTZSRECO0Tzescn
OP9Unb+miTTSl1tuu/gDULhYaCfDZu8bxIRaLt3tHV7falwbvUzO3wO8MQIDAQAB
o1MwUTAdBgNVHQ4EFgQUum/ad6XhlDl83w56t8OzQJSl/nQwHwYDVR0jBBgwFoAU
um/ad6XhlDl83w56t8OzQJSl/nQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
AQsFAAOCAQEAVPnYFFhYdAquC2g5k3mA+brhBuxFY+Rf9COE3u4lREJsXxjudsBR
1dE+n9Zla2andkEyu9KQZlTb0WE7WfxDgKEtYCzRYhvtj9xFKCjzncH1w4Z2iN/R
n8qmBWSFN5se0J/7uGsZ1YIcR8BsbkofmgnvBydUSXjNY7lbDOkY79gm/wykgdLe
TNOnRz+z6ofEkduBsxwSyY1Ck9CrRNklcfEW6YY0Re4FzUpBIWgeWqmxhIqeOWFI
eH7n4hqOrENTN7/GJvZH8PnjQj4Nx27cj+EW6xh5QMjYXkaxFFgGyMs/8AaresZZ
geieV/J2gfe+zBuG5h5cJ+9kR26d/0InUA==
-----END CERTIFICATE-----
25 changes: 25 additions & 0 deletions test/testdata/test_attach_second_leafcert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIENjCCAx6gAwIBAgIUEc3nCZYvXtlMHd+tLM7x4zueFYgwDQYJKoZIhvcNAQEL
BQAwgZkxCzAJBgNVBAYTAklOMQwwCgYDVQQIDANERUwxDDAKBgNVBAcMA0RFTDEa
MBgGA1UECgwRZXhhbXBsZWNsaWVudC5jb20xFTATBgNVBAsMDHNpZ3N0b3JlLXN1
YjEVMBMGA1UEAwwMc2lnc3RvcmUtc3ViMSQwIgYJKoZIhvcNAQkBFhVmb29AZXhh
bXBsZWNsaWVudC5jb20wHhcNMjQwMTE4MTAxNDA2WhcNMjkwMTE2MTAxNDA2WjCB
mzELMAkGA1UEBhMCSU4xDDAKBgNVBAgMA0RFTDEMMAoGA1UEBwwDREVMMRowGAYD
VQQKDBFleGFtcGxlY2xpZW50LmNvbTEWMBQGA1UECwwNc2lnc3RvcmUtbGVhZjEW
MBQGA1UEAwwNc2lnc3RvcmUtbGVhZjEkMCIGCSqGSIb3DQEJARYVZm9vQGV4YW1w
bGVjbGllbnQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5MdM
RkWjtryLneymMdkz+I8IB8t/6LSwS7M2olnQYV1byLopYraDxCTxIeaizoeeyoK+
F5HfwXid0X4vM/5PAdSjEq2Cf//+nnVJKQnAC96SCwQmUrKkzM69ASWsTCO3dK3d
iRTI/g6031tMDfkXj2nDDjnBGAl/YIuNSY4mUccrTaGfFbIHjCvQ3zHdsYi90vrx
miKaQRCwe2quE82ZcokkrxLQMM+qUha1TkJdKXAR28E2nZcnjcQFI5hrMMrc+PNb
CB20pZP/Mnw8tED7r+r/0LDs7GruCP+w/FH5K5E4cvyScMXYZ/TUTDv2rrTXzA8u
Rhq7xnEt9k7CQnpNSwIDAQABo3IwcDAfBgNVHSMEGDAWgBShacFO3pe6fgps4Icg
bDV5zS5cZTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DATBgNVHSUEDDAKBggrBgEF
BQcDAzAgBgNVHREEGTAXgRVmb29AZXhhbXBsZWNsaWVudC5jb20wDQYJKoZIhvcN
AQELBQADggEBAIJpBNO2/P3TYgp15vnBCCyDa9+BVy4C4CokM7COn24KXY8B6POT
Bk84/lI0Z6nKaSSO7wTWUkkf1UQy7eYuHPCyUMdaupbxnUtPj5+oQIh8X3wuuNzn
nfP++RBBx4qZwTCgdOj89CSw5eGSpPGEjPKacApn9cmZ6bk0ZHlKMQQRyRQ0tFdu
45Ou0r6LwZcf3kcZfSgEDzV2Kz5RKj1UID9vhQShgG0eNesfnSKY0NYxWb6u1tfZ
wHOx2N6wZ0g9tfvJxUcvkLlyg4AC6AOWQ6QINEjtJ4cq5VLkOJg2qjp7+NgfZJFl
yeAczjg+cqeX3jg+/iO9/GTokvXSHRTH85g=
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions test/testdata/test_attach_second_private_key
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA5MdMRkWjtryLneymMdkz+I8IB8t/6LSwS7M2olnQYV1byLop
YraDxCTxIeaizoeeyoK+F5HfwXid0X4vM/5PAdSjEq2Cf//+nnVJKQnAC96SCwQm
UrKkzM69ASWsTCO3dK3diRTI/g6031tMDfkXj2nDDjnBGAl/YIuNSY4mUccrTaGf
FbIHjCvQ3zHdsYi90vrxmiKaQRCwe2quE82ZcokkrxLQMM+qUha1TkJdKXAR28E2
nZcnjcQFI5hrMMrc+PNbCB20pZP/Mnw8tED7r+r/0LDs7GruCP+w/FH5K5E4cvyS
cMXYZ/TUTDv2rrTXzA8uRhq7xnEt9k7CQnpNSwIDAQABAoIBACZhtU840b2PplDJ
ahyE1y5FONCt+HifD9CzcWANd2NOWV60tMrF2hdnJzlLy1ag9Cf/hUrJA2QfC0Mh
S2QKr1CcTvuMNo+o8Bu/i5Wh+CFFpvTILnHDXNirepQdsOlZOKcPoFImNY5CA2BR
ndHeT3CVCs9xKw8QUNlusDZ97bncQhiTJ6Upqmd4432BVxk3uAvPuKlgjeyXQ2hQ
iYdNfWe+qQEqkOCV+JcDQDNXOb+l6bvfhECK/92xhCNu0U8hca5xy5nQlD/epJBn
ojzX+lyQxIs+T/sQF3IbN6pVZ5IGjgPx3LUw/0GSEAr++7SupFIJjgNDrDoOn7GA
7QufhOkCgYEA8g7IZd3PO4t3GK7bnX8yBOuGufwPkJlA2YS/Uh2cbW+YXPQEKqn8
HQysBjJCuxRnsOkAXoV3u3Ym/eph8Cz+FVqiPt33hYy81ZGGJyOmBUu/9C/Lghxt
D2NbJ7kNFEWe+qvoa13Z7r2VzQdBKjagoMPed3lkEovF14MNzvU2ZKUCgYEA8fS1
aJ2gcxShL4enPUXykxpbUP52VYJYO75ZLDwQmvlqiNK/EC8ZMCldMrFf1nMDFaG4
tx+pIizE3rA89ZRTPsj19G3aU1C/B+/LQFM/r+ZpdyaLs5BnPPaPYIEPt6Ad34/O
lxazRv6+FHJJ1EbZlmhsUXOdmMYvtYlJ4N83Fy8CgYBqPBixtI7OKGCFwcB7OCbg
x+niWIEQSmKO1NcPGBXeZdrt+N6XRvFyYmxhb8+fwc3cc/aIhXVOHgXw7Nw9B9If
1x5cDxkiUOlTpkHFjbzAmEVPy2Y63XT0Cvwny+y0l/W1OJuR+6e5QxWq3WM5Pq5y
wGQz9V/5T8Tt2APIcBCGTQKBgHJElpQktU0ENieDUklOyoQMk4nJ00sI9vCoMecB
Kvp1xol9tjxHcgbb0icJu/BEevVxXhImArOgHw3of7Gfbj0dnYLlipGEdeOirQPh
DRfeonpiGuIf1ZHmA8qYyTp4hQM7IF8cmmhyEIUJgLKfD03IXTeOeaRYHNoIT3rD
EHqDAoGADyUkL/6rQcHR04MgGCQX8qkQRDXlfUZps8idu5dnFmoRdzaHdITlWZgJ
V+deNWItvFmEWQdyt8aQ7r+SKbtVLw2R56KKXbMDPx2HxRyomHQymJBX/E7BSKj7
w02PrkC96WLnupa3RvXW35RJilTiVrPoCHhr2s/SxCXVNrACLeA=
-----END RSA PRIVATE KEY-----

0 comments on commit f43eb6b

Please sign in to comment.