From 9c5d8098cef3fbea146ec0b7465250df9c016e69 Mon Sep 17 00:00:00 2001 From: Pavol Ipoth Date: Wed, 30 Oct 2024 00:14:39 +0100 Subject: [PATCH] Use ed25519 instead of rsa in self signed certs --- docs/content/userguide/_index.md | 2 +- pkg/constant/constant.go | 1 - pkg/encryption/self_signed.go | 31 ++++++++++++++++++----------- tests/ca-config.json | 25 ----------------------- tests/ca-csr.json | 19 ------------------ tests/ca-key.pem | 27 ------------------------- tests/ca.pem | 23 --------------------- tests/proxy-csr.json | 4 ++-- tests/proxy-key.pem | 32 +++++------------------------- tests/proxy.pem | 34 +++++++++++--------------------- 10 files changed, 40 insertions(+), 158 deletions(-) delete mode 100644 tests/ca-config.json delete mode 100644 tests/ca-csr.json delete mode 100644 tests/ca-key.pem delete mode 100644 tests/ca.pem diff --git a/docs/content/userguide/_index.md b/docs/content/userguide/_index.md index de49f961..dcac233e 100644 --- a/docs/content/userguide/_index.md +++ b/docs/content/userguide/_index.md @@ -537,7 +537,7 @@ the proxy will use the default certificate. If you wish to verify the trust, you’ll need to generate a CA, for example. ``` bash -$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ca.key -out ca.pem +$ openssl req -x509 -nodes -days 365 -newkey ed2551 -keyout ca.key -out ca.pem $ bin/gatekeeper \ --enable-forwarding \ --forwarding-username=USERNAME \ diff --git a/pkg/constant/constant.go b/pkg/constant/constant.go index 13976ddf..47bf294b 100644 --- a/pkg/constant/constant.go +++ b/pkg/constant/constant.go @@ -78,7 +78,6 @@ const ( PKCECodeVerifierLength = 96 PATRefreshInPercent = 0.85 HTTPCompressionLevel = 5 - SelfSignedRSAKeyLength = 2048 SelfSignedMaxSerialBits = 128 CookiesPerDomainSize = 4069 RedisTimeout = 10 * time.Second diff --git a/pkg/encryption/self_signed.go b/pkg/encryption/self_signed.go index 64c8bba0..4f568f31 100644 --- a/pkg/encryption/self_signed.go +++ b/pkg/encryption/self_signed.go @@ -18,8 +18,8 @@ package encryption import ( "context" + "crypto/ed25519" "crypto/rand" - "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" @@ -44,7 +44,7 @@ type SelfSignedCertificate struct { // hostnames is the list of host names on the certificate hostnames []string // privateKey is the rsa private key - privateKey *rsa.PrivateKey + privateKey *ed25519.PrivateKey // the logger for this service log *zap.Logger // stopCh is a channel to close off the rotation @@ -67,14 +67,14 @@ func NewSelfSignedCertificate(hostnames []string, expiry time.Duration, log *zap zap.String("common_name", hostnames[0]), ) - key, err := rsa.GenerateKey(rand.Reader, constant.SelfSignedRSAKeyLength) + _, key, err := ed25519.GenerateKey(rand.Reader) if err != nil { return nil, err } // @step: create an initial certificate - certificate, err := CreateCertificate(key, hostnames, expiry) + certificate, err := CreateCertificate(&key, hostnames, expiry) if err != nil { return nil, err @@ -88,7 +88,7 @@ func NewSelfSignedCertificate(hostnames []string, expiry time.Duration, log *zap expiration: expiry, hostnames: hostnames, log: log, - privateKey: key, + privateKey: &key, cancel: cancel, } @@ -114,7 +114,11 @@ func (c *SelfSignedCertificate) rotate(ctx context.Context) error { return case <-time.After(ticker): } - c.log.Info("going to sleep until required for rotation", zap.Time("expires", expires), zap.Duration("duration", time.Until(expires))) + c.log.Info( + "going to sleep until required for rotation", + zap.Time("expires", expires), + zap.Duration("duration", time.Until(expires)), + ) // @step: got to sleep until we need to rotate time.Sleep(time.Until(expires)) @@ -154,7 +158,7 @@ func (c *SelfSignedCertificate) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Cer } // createCertificate is responsible for creating a certificate -func CreateCertificate(key *rsa.PrivateKey, hostnames []string, expire time.Duration) (tls.Certificate, error) { +func CreateCertificate(key *ed25519.PrivateKey, hostnames []string, expire time.Duration) (tls.Certificate, error) { // @step: create a serial for the certificate serial, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), constant.SelfSignedMaxSerialBits)) if err != nil { @@ -168,9 +172,8 @@ func CreateCertificate(key *rsa.PrivateKey, hostnames []string, expire time.Dura KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, NotAfter: time.Now().Add(expire), NotBefore: time.Now().Add(-30 * time.Second), - PublicKeyAlgorithm: x509.ECDSA, + PublicKeyAlgorithm: x509.Ed25519, SerialNumber: serial, - SignatureAlgorithm: x509.SHA512WithRSA, Subject: pkix.Name{ CommonName: hostnames[0], Organization: []string{"Gatekeeper"}, @@ -189,12 +192,18 @@ func CreateCertificate(key *rsa.PrivateKey, hostnames []string, expire time.Dura } // @step: create the certificate - cert, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) + cert, err := x509.CreateCertificate(rand.Reader, &template, &template, key.Public(), key) if err != nil { return tls.Certificate{}, err } + + pkcsPrivKey, err := x509.MarshalPKCS8PrivateKey(*key) + if err != nil { + return tls.Certificate{}, err + } + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert}) - keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) + keyPEM := pem.EncodeToMemory(&pem.Block{Type: "X25519 PRIVATE KEY", Bytes: pkcsPrivKey}) return tls.X509KeyPair(certPEM, keyPEM) } diff --git a/tests/ca-config.json b/tests/ca-config.json deleted file mode 100644 index 47f0a17a..00000000 --- a/tests/ca-config.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "signing": { - "default": { - "expiry": "17520h" - }, - "profiles": { - "server": { - "usages": [ - "signing", - "key encipherment", - "server auth" - ], - "expiry": "17520h" - }, - "client": { - "usages": [ - "signing", - "key encipherment", - "client auth" - ], - "expiry": "17520h" - } - } - } -} diff --git a/tests/ca-csr.json b/tests/ca-csr.json deleted file mode 100644 index ee4096b6..00000000 --- a/tests/ca-csr.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "CN": "Gatekeeper", - "CA": { - "expiry": "87600h" - }, - "key": { - "algo": "rsa", - "size": 2048 - }, - "names": [ - { - "C": "GB", - "L": "London", - "O": "Gatekeeper", - "OU": "Dev Environment", - "ST": "London" - } - ] -} diff --git a/tests/ca-key.pem b/tests/ca-key.pem deleted file mode 100644 index 548a86b6..00000000 --- a/tests/ca-key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAwpea54iKyQ+FEfMv3JUvdME0xGTLG7qFkNga3xFhwVXVxc8C -2golEEM/YkPd8msFNhaXGig7jv4bHIopYwTrvvt8GZirlPzh5jp1RO7nL9/UY84T -31tMDeUD2MtCFQhix9UnnY3sY0WFzUoq6hwxLbLklMeNPjkvWBfgth8YCxZNca9w -RejNeYKiL3kxcLJHldMkYkn9kbT1FUH229V8FVUrWIaOqi7NiTLNwFseY50EuZmp -U2psDlRRsPvcDJvjzPVIu+mkAjLTTTFHaQAkih9b4o8eXe1XC2vLwGo4Kn09ANbD -wN6/fed6N8SexDDZzgIFoeoglmzP/hdWqwoI6QIDAQABAoIBAQCk+LSqADdxF8hA -HIUCJDRUbowWyEDtZCdiUeQOI4VVzDhs+AC564najLiKzXC32YVUgrhdw6gipUlE -29kUipJ2mmxuouEscWvurLbI1yWGj+NXLdnpLVSAHx0wyblfbXmZYxuv1ieHTeSO -04cobPhAfv6NJ9SV4RNDQxMOM7RFiImGmsusSrSdqccWkviKPe8nnzI94XzP/ilR -RhF92b4jZp7rB6QA7O3bPmv1KkTOXJWGRyFmYjtO5NM+liyRjxz6Mu08/CM/6/jz -XGIHdUpJ+qBUTv21/phR9G+L/FNwlJpOjg4dhv1l2YnIW9VZMfTOvOHCuUscJX62 -OFDaAo71AoGBAMnI019ibSeoA9EljMEx52VU5tqDQqU/nidihmYATQTH8oDL6uB4 -So+CUhFg3j6dPllXxd2qm5Kr2RdOSJVr7RYA0wQmtWcOCRckSvk23B5cl+6XAQSH -vRC7YZuim2MZM/arO6U+D+ZjgX2g5PcUuLioNi966OK1wvSwXgVksVUnAoGBAPbg -FGH8VGtjaPbPULd0NwCxcA5Mw2h6JIJw6qt+gW4rYgBSBBZcF6ivq2XeQRUETXvc -Sv6K9Rfd+OX4AFmppV6pca583FMy4BaqD75zRrJ1G5AT7Ax6vbvyCHnrD5zKlnq2 -WCeTcNYDHxB7CV+Ea2YYrhL28EvA5XJdB7EJXRtvAoGAXURqDuibs3zBZuaITLQY -VIoNump5X5AsNeAgZv00nEUfHdEjW2W+cN63uDiiAScFLp6XYoH9LqonydHxUr9z -8nunDYAm0N937C5mSRLGY3JA95LscX+cMCOsVheu4vs/PYCgLRymlMLhk4PO0TXO -u+tkQEX7Zu7Ekf0DOFL2dHkCgYBgVR3/Ajxazya1MD5555JS5eoo2lFh4k9+ytr3 -YlzVBX6vS1Gm+/aLb0j9bhWNQumNTG/DFav/zTEDY5uXYThTUOE4SiabHH4Ouft8 -wHS0zDeeJ/fzAq4ouZAPKucjsnW3mpGZl9Hu4LbtcmU87WoPI9BBPDSWCsY9swl+ -Tn4TZwKBgQCBCzAdy/1VEOiOREtZufuUnbLi3WotymZYEyHbGwp+o6ZVvgkoH3PZ -MyS4bKi8TTRG+KTPvIxGcEnLF+qp+LqQbjLQE/sShW9q46ZLkds6Ku1wndVaKBdg -2KWTp04a5MpEV8sSiEtdG3Ed2y6dY9nKzlIR4clUVOcvYT6HXqIwGw== ------END RSA PRIVATE KEY----- diff --git a/tests/ca.pem b/tests/ca.pem deleted file mode 100644 index 7add15c0..00000000 --- a/tests/ca.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID6jCCAtKgAwIBAgIUAi2xiTeqKlnxLNnrGSj2vgkJzNUwDQYJKoZIhvcNAQEL -BQAwezELMAkGA1UEBhMCR0IxDzANBgNVBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9u -ZG9uMRcwFQYDVQQKEw5LZXljbG9hayBQcm94eTEYMBYGA1UECxMPRGV2IEVudmly -b25tZW50MRcwFQYDVQQDEw5LZXljbG9hayBQcm94eTAeFw0xNjA0MjMwOTE1MDBa -Fw0yNjA0MjEwOTE1MDBaMHsxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24x -DzANBgNVBAcTBkxvbmRvbjEXMBUGA1UEChMOS2V5Y2xvYWsgUHJveHkxGDAWBgNV -BAsTD0RldiBFbnZpcm9ubWVudDEXMBUGA1UEAxMOS2V5Y2xvYWsgUHJveHkwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCl5rniIrJD4UR8y/clS90wTTE -ZMsbuoWQ2BrfEWHBVdXFzwLaCiUQQz9iQ93yawU2FpcaKDuO/hsciiljBOu++3wZ -mKuU/OHmOnVE7ucv39RjzhPfW0wN5QPYy0IVCGLH1SedjexjRYXNSirqHDEtsuSU -x40+OS9YF+C2HxgLFk1xr3BF6M15gqIveTFwskeV0yRiSf2RtPUVQfbb1XwVVStY -ho6qLs2JMs3AWx5jnQS5malTamwOVFGw+9wMm+PM9Ui76aQCMtNNMUdpACSKH1vi -jx5d7VcLa8vAajgqfT0A1sPA3r9953o3xJ7EMNnOAgWh6iCWbM/+F1arCgjpAgMB -AAGjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1Ud -DgQWBBRVovC8Fu3J1oxaUX2cQyroP+vArTAfBgNVHSMEGDAWgBRVovC8Fu3J1oxa -UX2cQyroP+vArTANBgkqhkiG9w0BAQsFAAOCAQEAb8nttca4vZYgiYxtwfM6HWRH -dQbGNfEX5nEz84lHmmP46oItfh7xxbD2boDRUa/FQ8nDw9bG8FZWuxYF4beka097 -auHbTTF1RmbyRHD4auHJAOO0RLCe9xQTGI4hAqTq4L7Zpral/4Ss7q1V122I6OB3 -0pgNM+9Cqrlur6JSociGdEv6l0GBE8jjRSOFQaBYWq46sb1T8IfxUpcT/UTyTceQ -lW/vDF4V4CtrB4Rn01CTN4zcG06bo7m8idxnKoSD51PvXioVoX44g3j5PJvvOdH0 -7yMcfENwj3QL98KNeUXzyDqjL8krmfH0+vNyoI+fhfsNEcJN9NSrD6RUtm8zcg== ------END CERTIFICATE----- diff --git a/tests/proxy-csr.json b/tests/proxy-csr.json index dfc756fc..8d38a0de 100644 --- a/tests/proxy-csr.json +++ b/tests/proxy-csr.json @@ -5,8 +5,8 @@ "127.0.0.1" ], "key": { - "algo": "rsa", - "size": 2048 + "algo": "ecdsa", + "size": 256 }, "names": [ { diff --git a/tests/proxy-key.pem b/tests/proxy-key.pem index 972eca34..36ccf20b 100644 --- a/tests/proxy-key.pem +++ b/tests/proxy-key.pem @@ -1,27 +1,5 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEAwNM8DDZe1IIw1Y2h5Rit9DJr4YKkUJsGicCKBAj47Z9r6O3Q -t1V8T6t13eR7M1/7nEqjWx4MpRMoAV7QhtmcyuEvu/XKSkQ4MAyKLiCwvARSAs3m -51ZIw+TVJhv3DNxn168OgPN7FrbkTkzFJATf+lx/1RVNqfym5bXYj5k+pNuFttzU -kjEkEnNRW5leppIUAG7AQfM9SbIAL+7nmvBrIVVaAk6kmbFk4H8LaMrQYh9uzmx3 -121MraH1ik4pwuDpLzUl3P1WC8N972oSm5MWffgdhRu3cmD10wY7xsVIUKQi/TG6 -vI1MYPra9vQAusawUY5N4xx/qdbUiB0a4YacYQIDAQABAoIBAQCaOpqF3hsdeICc -3usF9iZ08rttJXRN8KFbHwCFV7PbRC8ooMbXTO3gP3FIKM8N+ZCjouNkJvXQNzFB -X1gE9Bu//juS6HaDzmruq6j+WjFiQUZjbdNpZ49N+EMwdx+0TrpUPnWoWJc0RNb5 -ddgdBjUr6D5q7d4vv6CyjS+JM/ZyHqvHhrtaf2BAGCFtIPFL4xr4tw4qhIqcq1X1 -PgMwiUnjx4SmVlFkhYBOwax+MBtjgNaCC84vKPn753lFfqbmSF/GkY4olS1UbP0v -WhaZmf1KwQlVN9qDtjp+HvPpwqhqX3pooQ9cqoAzuNUoFK/koM7ZjgNkoP1R7x+Y -OZuZxE1NAoGBANNHlmE+xbZPHCLb7Gx2qI0YTlcVoqBL+7Bt7abiQgoZngiv3ljq -rldtQEXaBTw24cQGRLZfJIhN1Zc6InZeYWKExeW4V8UGh4ghbuhSkrAGiFgunjil -+2buKKfGG9wLRKKL+Iv3iJxQ10NPKpHxkcz9NlzLNwmfRjPuVcOgsSb/AoGBAOmj -q5GQlHGKbvt8qRc4pbFWYacxkProsV78wtnyE8cZg+jTXoFriLTPLnG27sArFWBW -/PLiMSJQMUysXbVK67XFApvJHARMPzWyXMCD0/p5VvOKogHhNmAhcOuCtS6dIlWJ -yUWs9PU5q4lP9WzseTMAM9YuTk4fQBAVrYQ8RJyfAoGAGdyLZb/fR5+LXCD7YZNs -skilXjeBvolOd5wdGO5dEwtrsriESPIBASaYVXSIa4R0QiBaTNB8kkqkuGwfR8np -tbt21dWouK9B68Hb54gj+HP0QIcESv7WNRU12MOBKYAfmJ31gHx+NlQW5WBNX6vo -IuVjwBwH0p+yYizsRpPm21UCgYEA1nsk7n1+eHjwBzhadfHP0euNvBG5mUzyP1Pk -gHVFiLo4qQ0ZLdAM8IddiJC5vnoOpqFUlpflKS3bBBsb72j216gjC+ZkLOHeCSpT -EXwzpjWsB+kVbopUA43PfrRAJamkskfKGId9XH1zpptbn4G6hYJDE/Twd7Eie2Gb -J9C339sCgYEAwTVJmmoEK3Use7hINiFiP19HQOj8+PDfb0jbtM2J9Bgd6LJEEbo9 -rn3xdIc0dnr48Rna8T+RxwFaSrc3h2yXmPTygYmWbC36qnXvBhsqCQ5KtLKUVes2 -6cFDdCkWpLJH+9xIfHs1EtA05apK3+pQtMVqCJg/evmWad+e1q+qMow= ------END RSA PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIDzEWDbI3C978OX7/yOX1xmnmLynnEVY0nu7jYDD/jBMoAoGCCqGSM49 +AwEHoUQDQgAE9LJY8+DREb/KzT3ybvzJsxq0QJi6WXz3rqliZ2jjSosaDCdCCNFm +gq+KxNjqhoP4vAkfTSY9sPxmLiXldQoVmQ== +-----END EC PRIVATE KEY----- diff --git a/tests/proxy.pem b/tests/proxy.pem index f22633a4..ee2e823e 100644 --- a/tests/proxy.pem +++ b/tests/proxy.pem @@ -1,24 +1,14 @@ -----BEGIN CERTIFICATE----- -MIIEBzCCAu+gAwIBAgIUHmkQU1W8HzjP6gQNGWxpj1OOg1AwDQYJKoZIhvcNAQEL -BQAwezELMAkGA1UEBhMCR0IxDzANBgNVBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9u -ZG9uMRcwFQYDVQQKEw5LZXljbG9hayBQcm94eTEYMBYGA1UECxMPRGV2IEVudmly -b25tZW50MRcwFQYDVQQDEw5LZXljbG9hayBQcm94eTAeFw0xNjA0MjMwOTE1MDBa -Fw0xODA0MjMwOTE1MDBaMGsxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24x -DzANBgNVBAcTBkxvbmRvbjEXMBUGA1UEChMOS2V5Y2xvYXkgUHJveHkxCzAJBgNV -BAsTAklUMRQwEgYDVQQDEwsqLmxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAMDTPAw2XtSCMNWNoeUYrfQya+GCpFCbBonAigQI+O2fa+jt -0LdVfE+rdd3kezNf+5xKo1seDKUTKAFe0IbZnMrhL7v1ykpEODAMii4gsLwEUgLN -5udWSMPk1SYb9wzcZ9evDoDzexa25E5MxSQE3/pcf9UVTan8puW12I+ZPqTbhbbc -1JIxJBJzUVuZXqaSFABuwEHzPUmyAC/u55rwayFVWgJOpJmxZOB/C2jK0GIfbs5s -d9dtTK2h9YpOKcLg6S81Jdz9VgvDfe9qEpuTFn34HYUbt3Jg9dMGO8bFSFCkIv0x -uryNTGD62vb0ALrGsFGOTeMcf6nW1IgdGuGGnGECAwEAAaOBkjCBjzAOBgNVHQ8B -Af8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNV -HQ4EFgQUH6wX3y5G+00o/oY2BRM8De3A2QcwHwYDVR0jBBgwFoAUVaLwvBbtydaM -WlF9nEMq6D/rwK0wGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3 -DQEBCwUAA4IBAQCbN2zfXg5xyaMtbAbXaHsBiApan++cgJZf5pxm7X8NbVHDotXh -Y1fQkejN/dX+C8aSL83pxi19WZBQXuq50i+ocNtGIYyAlXL7c1j++CWeTY64m3kO -FkpismDobvwdGkzPMR1xUZdAvxywuYTQrmZKZyVNNVAwidVPJ1ZyqobY8R2SFaai -vNm/J8U3lnItDdLIJkfACe1mq/AzwdzZ4i+U3FnW7yJEnDicEY4aIcZg0zNSqoQ/ -EQMrH0O5ibGYsXInuQBXIIKygG7No4PMKYJtLwrx1sjKVKrqmDg4gBdLzjMzlY1r -PbDsAkmVmOEhOB0zPNtUm+Or2l+KddUXCs/3 +MIICKTCCAdCgAwIBAgIIch1hRdLotKIwCgYIKoZIzj0EAwIwazELMAkGA1UEBhMC +R0IxDzANBgNVBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMRcwFQYDVQQKEw5L +ZXljbG9heSBQcm94eTELMAkGA1UECxMCSVQxFDASBgNVBAMTCyoubG9jYWxob3N0 +MB4XDTI0MTAyOTIyMTAyMVoXDTI1MDEyOTA0MTUyMVowazELMAkGA1UEBhMCR0Ix +DzANBgNVBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMRcwFQYDVQQKEw5LZXlj +bG9heSBQcm94eTELMAkGA1UECxMCSVQxFDASBgNVBAMTCyoubG9jYWxob3N0MFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9LJY8+DREb/KzT3ybvzJsxq0QJi6WXz3 +rqliZ2jjSosaDCdCCNFmgq+KxNjqhoP4vAkfTSY9sPxmLiXldQoVmaNeMFwwDgYD +VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV +HRMBAf8EAjAAMB0GA1UdDgQWBBS1iJwIhIK7PLspuzPVBppVeYpEbjAKBggqhkjO +PQQDAgNHADBEAiAdq5gSWeY5r8Q3Gcwl6QWKMV0isio3+gMjb8kupHCO3gIgJFT5 +S+DOPOTC5G73V5f8zlC21CO2RtKyGwJBLE1B530= -----END CERTIFICATE-----