Skip to content
Snippets Groups Projects
Unverified Commit 5e119f5c authored by Robert Roland's avatar Robert Roland Committed by GitHub
Browse files

Allow specifying the server cert chain for MongoDB (#12564)

This will allow the user to specify the server's certificate chain (the
public CA certs) or the server's private key if it's a self-signed cert
with no CA.

Resolves #3877

[ci mongo]
parent 41592607
No related branches found
No related tags found
No related merge requests found
Showing
with 313 additions and 18 deletions
......@@ -60,6 +60,11 @@ const DATABASE_DETAIL_OVERRIDES = {
{ name: t`Password`, value: "password" },
],
}),
"ssl-cert": (engine, details) => ({
title: t`Server SSL certificate chain`,
placeholder: t`Paste the contents of the server's SSL certificate chain here`,
type: "text",
}),
};
const AUTH_URL_PREFIXES = {
......@@ -200,6 +205,11 @@ function getFieldsForEngine(engine, details) {
continue;
}
// NOTE: special case to hide the SSL cert field if SSL is disabled
if (field.name === "ssl-cert" && !details["ssl"]) {
continue;
}
const overrides = DATABASE_DETAIL_OVERRIDES[field.name];
// convert database details-fields to Form fields
fields.push({
......
......@@ -28,6 +28,11 @@ driver:
- name: use-srv
type: boolean
default: false
- merge:
- ssl
- name: ssl-cert
type: string
display-name: Server SSL certificate chain
connection-properties-include-tunnel-config: true
init:
- step: load-namespace
......
......@@ -77,6 +77,9 @@
#"^java.net.ConnectException: Connection refused$"
(driver.common/connection-error-messages :ssh-tunnel-connection-fail)
#".*javax.net.ssl.SSLHandshakeException: PKIX path building failed.*"
(driver.common/connection-error-messages :certificate-not-trusted)
#".*" ; default
message))
......
(ns metabase.driver.mongo.util
"`*mongo-connection*`, `with-mongo-connection`, and other functions shared between several Mongo driver namespaces."
(:require [clojure.tools.logging :as log]
(:require [clojure.string :as str]
[clojure.tools.logging :as log]
[metabase
[config :as config]
[util :as u]]
[metabase.driver.util :as driver.u]
[metabase.models.database :refer [Database]]
[metabase.util
[i18n :refer [trs tru]]
......@@ -61,14 +63,18 @@
doesn't support `.serverSelectionTimeout` or `.sslEnabled`. `additional-options`, a String like
`readPreference=nearest`, can be specified as well; when passed, these are parsed into a `MongoClientOptions` that
serves as a starting point for the changes made below."
^MongoClientOptions [& {:keys [ssl? additional-options]
:or {ssl? false}}]
(-> (client-options-for-url-params additional-options)
client-options->builder
(.description config/mb-app-id-string)
(.connectTimeout connection-timeout-ms)
(.serverSelectionTimeout connection-timeout-ms)
(.sslEnabled ssl?)))
^MongoClientOptions [& {:keys [ssl? additional-options ssl-cert]
:or {ssl? false, ssl-cert ""}, :as details}]
(let [client-options (-> (client-options-for-url-params additional-options)
client-options->builder
(.description config/mb-app-id-string)
(.connectTimeout connection-timeout-ms)
(.serverSelectionTimeout connection-timeout-ms)
(.sslEnabled ssl?))]
(if (not (str/blank? ssl-cert))
(-> client-options
(.socketFactory (driver.u/socket-factory-for-cert ssl-cert)))
client-options)))
;; The arglists metadata for mg/connect are actually *WRONG* -- the function additionally supports a 3-arg airity
;; where you can pass options and credentials, as we'd like to do. We need to go in and alter the metadata of this
......@@ -97,8 +103,8 @@
(format "mongodb+srv://%s:%s@%s/%s" user pass host authdb))
(defn- normalize-details [details]
(let [{:keys [dbname host port user pass ssl authdb tunnel-host tunnel-user tunnel-pass additional-options use-srv]
:or {port 27017, pass "", ssl false, use-srv false}} details
(let [{:keys [dbname host port user pass ssl authdb tunnel-host tunnel-user tunnel-pass additional-options use-srv ssl-cert]
:or {port 27017, pass "", ssl false, use-srv false, ssl-cert ""}} details
;; ignore empty :user and :pass strings
user (when (seq user)
user)
......@@ -115,7 +121,8 @@
:dbname dbname
:ssl ssl
:additional-options additional-options
:srv? use-srv}))
:srv? use-srv
:ssl-cert ssl-cert}))
(defn- fqdn?
"A very simple way to check if a hostname is fully-qualified:
......@@ -129,11 +136,11 @@
replica list could easily provided instead of a single host.
Using SRV automatically enables SSL, though we explicitly set SSL to true anyway.
Docs to generate URI string: https://docs.mongodb.com/manual/reference/connection-string/#dns-seedlist-connection-format"
[{:keys [host port user authdb pass dbname ssl additional-options]}]
[{:keys [host port user authdb pass dbname ssl additional-options ssl-cert], :as details}]
(if-not (fqdn? host)
(throw (ex-info (tru "Using DNS SRV requires a FQDN for host")
{:host host}))
(let [conn-opts (connection-options-builder :ssl? ssl, :additional-options additional-options)
(let [conn-opts (connection-options-builder :ssl? ssl, :additional-options additional-options, :ssl-cert ssl-cert)
authdb (if (seq authdb)
authdb
dbname)
......@@ -145,11 +152,12 @@
"Connection info for Mongo. Returns options for the fallback method to connect
to hostnames that are not FQDNs. This works with 'localhost', but has been problematic with FQDNs.
If you would like to provide a FQDN, use `srv-connection-info`"
[{:keys [host port user authdb pass dbname ssl additional-options]}]
[{:keys [host port user authdb pass dbname ssl additional-options ssl-cert], :as details}]
(let [server-address (mg/server-address host port)
credentials (when user
(mcred/create user authdb pass))
^MongoClientOptions$Builder opts (connection-options-builder :ssl? ssl, :additional-options additional-options)]
^MongoClientOptions$Builder opts (connection-options-builder :ssl? ssl, :additional-options additional-options,
:ssl-cert ssl-cert)]
{:type :normal
:server-address server-address
:credentials credentials
......
......@@ -51,7 +51,10 @@
(deferred-tru "Looks like your username is incorrect.")
:username-or-password-incorrect
(deferred-tru "Looks like the username or password is incorrect.")})
(deferred-tru "Looks like the username or password is incorrect.")
:certificate-not-trusted
(deferred-tru "Server certificate not trusted - did you specify the correct SSL certificate chain?")})
;; TODO - we should rename these from `default-*-details` to `default-*-connection-property`
......
......@@ -7,7 +7,12 @@
[driver :as driver]
[util :as u]]
[metabase.util.i18n :refer [trs]]
[toucan.db :as db]))
[toucan.db :as db])
(:import java.io.ByteArrayInputStream
[java.security.cert CertificateFactory X509Certificate]
java.security.KeyStore
javax.net.SocketFactory
[javax.net.ssl SSLContext TrustManagerFactory X509TrustManager]))
(def ^:private can-connect-timeout-ms
"Consider `can-connect?`/`can-connect-with-details?` to have failed after this many milliseconds.
......@@ -97,3 +102,44 @@
;; TODO - maybe we should rename `details-fields` -> `connection-properties` on the FE as well?
[driver {:details-fields props
:driver-name (driver/display-name driver)}])))
;;; +----------------------------------------------------------------------------------------------------------------+
;;; | TLS Helpers |
;;; +----------------------------------------------------------------------------------------------------------------+
(defn- dn-for-cert
[^X509Certificate cert]
(.. cert getSubjectX500Principal getName))
(defn generate-keystore-with-cert
"Generates a `KeyStore` with custom certificates added"
^KeyStore [cert-string]
(let [cert-factory (CertificateFactory/getInstance "X.509")
cert-stream (ByteArrayInputStream. (.getBytes ^String cert-string "UTF-8"))
certs (.generateCertificates cert-factory cert-stream)
keystore (doto (KeyStore/getInstance (KeyStore/getDefaultType))
(.load nil nil))
;; this TrustManagerFactory is used for cloning the default certs into the new TrustManagerFactory
base-trust-manager-factory (doto (TrustManagerFactory/getInstance (TrustManagerFactory/getDefaultAlgorithm))
(.init ^KeyStore (cast KeyStore nil)))]
(doseq [cert certs]
(.setCertificateEntry keystore (dn-for-cert cert) cert))
(doseq [^X509TrustManager trust-mgr (.getTrustManagers base-trust-manager-factory)]
(when (instance? X509TrustManager trust-mgr)
(doseq [issuer (.getAcceptedIssuers trust-mgr)]
(.setCertificateEntry keystore (dn-for-cert issuer) issuer))))
keystore))
(defn socket-factory-for-cert
"Generates an `SocketFactory` with the custom certificates added"
^SocketFactory [cert-string]
(let [keystore (generate-keystore-with-cert cert-string)
;; this is the final TrustManagerFactory used to initialize the SSLContext
trust-manager-factory (TrustManagerFactory/getInstance (TrustManagerFactory/getDefaultAlgorithm))
ssl-context (SSLContext/getInstance "TLS")]
(.init trust-manager-factory keystore)
(.init ssl-context nil (.getTrustManagers trust-manager-factory) nil)
(.getSocketFactory ssl-context)))
(ns metabase.driver.util-test
(:require [clojure.test :refer :all]
[metabase.driver.util :as sut]))
;; if the CA certificate (ca.pem) used in this test is regenerated,
;; you'll need to update this DN
(def ^:private test-ca-dn
"ou=www,o=someone,l=seattle,st=washington,c=us")
;; if the server certificate (server.pem) used in this test is regenerated,
;; you'll need to update this DN
(def ^:private test-server-dn
"cn=server.local,ou=www,o=someone,l=seattle,st=washington,c=us")
(deftest test-generate-keystore-with-cert
(testing "a proper CA file is read"
(let [cert-string (slurp "./test_resources/ssl/ca.pem")
keystore (sut/generate-keystore-with-cert cert-string)]
(is (true? (.containsAlias keystore test-ca-dn)))))
(testing "bad cert provided"
(is (thrown? java.security.cert.CertificateException
(sut/generate-keystore-with-cert "fooobar"))))
(testing "multiple certs are read"
(let [cert-string (str (slurp "./test_resources/ssl/ca.pem")
(slurp "./test_resources/ssl/server.pem"))
keystore (sut/generate-keystore-with-cert cert-string)]
(is (true? (.containsAlias keystore test-server-dn)))
(is (true? (.containsAlias keystore test-ca-dn)))))
(testing "can create SocketFactory for CA cert"
;; this is a tough method to test - the resulting `SSLSocketFactory`
;; doesn't have any public members to access the underlying `KeyStore`
;; so the best we can do is make sure it doesn't throw anything on
;; execution
(is (instance? javax.net.ssl.SSLSocketFactory
(sut/socket-factory-for-cert (slurp "./test_resources/ssl/ca.pem"))))))
# test certificates
These certs are test certificates for running a service as "localhost".
`ca-csr.json` is the CSR for generating the CA
`ca-key.pem` contains the CA's private key
`ca.pem` contains the CA's public key (this is what you need to "trust")
`server-csr.json` is the CSR for generating the server key
`server.key` contains a private key for a certificate for the `serverd` server
`server.pem` contains the public key for `server.key`
These were generated with [cfssl](https://github.com/cloudflare/cfssl)
CA generation:
```sh
cfssl genkey -initca ca-csr.json | cfssljson -bare -stdout
```
Server certificate generation:
```sh
cfssl gencert -ca ca.pem -ca-key ca-key.pem -hostname=127.0.0.1,localhost server-csr.json | cfssljson -bare -stdout
```
{
"hosts": [
"127.0.0.1"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Seattle",
"O": "Someone",
"OU": "WWW",
"ST": "Washington"
}
]
}
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA2iKfXDh1jR3wkRTwJ0FuCdVUoIqDOHsswRPxGOS0iLCROXs8
qt5KupDPQFxpoEG+YPKejJ3dejA1ziVVgMU3fAERofsBvtpWAUbkRFbLWEYJl3YX
JSE5nZ1Qap+eaDzptGKqm8K4iLZed8p0H/HIbACIjhRQzadKi4M7OTkwQfIXa9Tc
zAxxHhJ3DiNuTb7eC6Jw6WoUfE/jQzrKbgmZkq29NK3/6XcWtMH9jvEEfCmdBZyj
xBCMDVa3E1UfZ7+KjGPTQ9PsaCKKyGhzrP4fh2bWTvsP91VWp/DdK3g8HHmpWICF
fwHYI1iCbY4+dQm7L/iOfsBH++AB6uVGlD8w5wIDAQABAoIBAHITQyW2PPtkmec1
fPX6iLJJxy0B4ufJurjqVd5/1E3bkMbvxOVSxN/WVRxCd9agKxCGMRY2hJme1rSM
368s8/w8jt0X6GzHv8yBJ2T5wvPSBLgZwLbhLkFYALMR8IRwvoNgSfqVFW4heTvK
O3ptNjQM/1zWEP/LqfdV1MXzO2JwYZ6JOm5snT+20cJz3CTZvxJEtWfDCNHaIQDp
JI70rpnYyXLkneW7yqht46WaENSmwcTgeHAT61wSm1zCHBUoIedUE/okILeiTaYk
09pEhIbl517B1l99QAryhDnKIHQRoFO63PocMbgPVD3o65qH97Slb63M3S40oIkz
so2RK1kCgYEA/xIQFQLSnBhXn3DsRKyeS1Sgpv/Cf3CA/3yAcS7ScfJ58lejjrR+
OAtrU7riuT0Ibbm+8IUnl24u/E/bKoH2I9G6CmyorNcHCSJf5QWDA362+MJe33SI
mfn5S1Of1Schqh4FfaIIrzTlFZDU1oQoYubH/CKbKy07DuHZC5I9cG0CgYEA2u4a
+HHNo8gKDVUQRbOjJ4VYJxziWthaAlNzdc1GXanIX0xo24JjQQhFXv7wpP52Wwha
/2R+V0zspoibMmJO30hMfxfWqlvwmZHgmIVIdfZ8+0uK1F2TLG+QLxZiYDRc3x9E
nE+a/nVVZ0A5MHZJn7gQoy/TIrcK14TrTpsM2iMCgYAtKLKGNci58ClbRi/efL1N
0v7acj+qNm3wTcejwklp+ScT++YuNtB99a+b1GOdriuW2aLvjHOVAOH6s9y2qum8
L76DZ/d5GlzZhid6Mb6fWMjmQ+tuHoCs2jAD4RtULqhsKQKJ2q007+V7KvgzvpQz
5m4TusDEJS7mlJ/Lx6lvBQKBgCOdGiwSLzaWYvQ6QzRjfYX/ThDGxResHDBGrQCb
zPeNl/fQsToMIuNAWjCS3kio0E4MtOjYyyiebdzFWiG/Fj+CPldqZFRAMop4zYVi
ISB3YWtrpYDYXAmdeGIAjS5DNlxhdMLMvFTqd2MdcnAsvdtKkQJK1FjQV+YpTDH0
TQnrAoGAPdkfTz4tnG51tIG5lAK9755AKY9KoDmRWI18mKYm2yDs0+TRoZ43bEQ4
qNp8h/NN7ljNCQ2pBLcaw1DAqpFVhBA/olpsrp1jPoJ0QXYfT4r4teLCi4CZSgoK
AFNbyf2aNS5JhjizN69au5gpLbWdJWhrsCiN843HcD50sz766Dc=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE REQUEST-----
MIICuzCCAaMCAQAwVDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
EDAOBgNVBAcTB1NlYXR0bGUxEDAOBgNVBAoTB1NvbWVvbmUxDDAKBgNVBAsTA1dX
VzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANoin1w4dY0d8JEU8CdB
bgnVVKCKgzh7LMET8RjktIiwkTl7PKreSrqQz0BcaaBBvmDynoyd3XowNc4lVYDF
N3wBEaH7Ab7aVgFG5ERWy1hGCZd2FyUhOZ2dUGqfnmg86bRiqpvCuIi2XnfKdB/x
yGwAiI4UUM2nSouDOzk5MEHyF2vU3MwMcR4Sdw4jbk2+3guicOlqFHxP40M6ym4J
mZKtvTSt/+l3FrTB/Y7xBHwpnQWco8QQjA1WtxNVH2e/ioxj00PT7Ggiishoc6z+
H4dm1k77D/dVVqfw3St4PBx5qViAhX8B2CNYgm2OPnUJuy/4jn7AR/vgAerlRpQ/
MOcCAwEAAaAiMCAGCSqGSIb3DQEJDjETMBEwDwYDVR0RBAgwBocEfwAAATANBgkq
hkiG9w0BAQsFAAOCAQEAG1WZK1w8ncFLS/9pknj/a1KrI714lB8a2dtbw8ste4eo
ItJbUU+nQCAlABZD7Evm6hE03gDVkWUs//WIIURgEZ+/YJA8Ja5oxPPbZuJ6kD43
6YCXFAKeINNam8DUzjvKmN+zW7x6XBNpGEroVNpMyyFw/UQ2FNA4UZ9F3OW7hZDM
8+O0vLpzAZlViTCC2K/XZKpFMXFL/FeqT+HO4pDGM0w6qWK2s90aSXk91gDhEQSD
kLLdcD04CGE/q2iOCr9faCX4G1X/qPhTKOW3PDGnWBSh7vAbh4VZbFPmygJJCDq1
TGpkJ8Y+xOSAkDmz2ANAPcvpcUoB9jb1vSwpT7cyUA==
-----END CERTIFICATE REQUEST-----
-----BEGIN CERTIFICATE-----
MIIDiTCCAnGgAwIBAgIUO1jCPUE8k8rP8XOK11UUuYUYJBgwDQYJKoZIhvcNAQEL
BQAwVDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
B1NlYXR0bGUxEDAOBgNVBAoTB1NvbWVvbmUxDDAKBgNVBAsTA1dXVzAeFw0yMDA1
MjAyMzMxMDBaFw0yNTA1MTkyMzMxMDBaMFQxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRAwDgYDVQQKEwdTb21lb25l
MQwwCgYDVQQLEwNXV1cwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
Ip9cOHWNHfCRFPAnQW4J1VSgioM4eyzBE/EY5LSIsJE5ezyq3kq6kM9AXGmgQb5g
8p6Mnd16MDXOJVWAxTd8ARGh+wG+2lYBRuREVstYRgmXdhclITmdnVBqn55oPOm0
YqqbwriItl53ynQf8chsAIiOFFDNp0qLgzs5OTBB8hdr1NzMDHEeEncOI25Nvt4L
onDpahR8T+NDOspuCZmSrb00rf/pdxa0wf2O8QR8KZ0FnKPEEIwNVrcTVR9nv4qM
Y9ND0+xoIorIaHOs/h+HZtZO+w/3VVan8N0reDwcealYgIV/AdgjWIJtjj51Cbsv
+I5+wEf74AHq5UaUPzDnAgMBAAGjUzBRMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBTyTkr7Fe4TiMFIZesDF534Llxu2DAPBgNVHREE
CDAGhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBGuGhoSM4RxYGUNaJBd28btt2l
Yboh9M80tJ68+jetpxTsTqOW9kr3o7R0a3fJ72G/6r6OW7K3Ni0C+tYY+X00Bk7t
simU7h4bpe1W/IrSQE2d66Apc6A8aqqnQRHdH0F4lXOkEJ3shtGU8NsXcPFRK/2h
gag0HnkZ7H4NIZnHPxpzZUrI2iLHADIjFOk0IuS7irh2HHYYQ75Z4lrfDNU+Kgad
402I+D8rUBn2XR+vYiEbReHvsbERCbDYOcZR0NUgRbcJKdn12bBARMnSmPF7HGD9
pn73GpS8RMTFCen0OfzukkYGClCiRDNEyrJg91XHBUYDRQyQKmGDcqGNLbil
-----END CERTIFICATE-----
{
"hosts": [
"127.0.0.1",
"localhost"
],
"key": {
"algo": "rsa",
"size": 2048
},
"CN": "server.local",
"names": [
{
"C": "US",
"L": "Seattle",
"O": "Someone",
"OU": "WWW",
"ST": "Washington"
}
]
}
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAyA6at0a5AYpZhG4AxL8aJD0dZDHAfvq//WLVRi3AqGYnIQeT
kctSlNr8mqWkok3YF3k8wa0QKvc31h10bBDPw0mC1MjgnGacauelM3yKS9YgmCr+
cljpOgRXFlLDsxEJgBdAGCmwf3dt4MTdTPsWUiTiEbXthXZplL0eZ5xhdKgttaoa
HZdc2bYEVoQ2DUKPEqZCC6Nv0BLnUTmPoXIwTmzP3hkKQFRrRj4KZQLiRs4JpY20
+nLmRcx5sTxU02Guoc0yErijvCel6UL8NNz2FnpQpv9qKRtw6FdmkWHKb7p6J3cV
TfpjXjFoWA5MoRv3rcnban9IED5eBwa5CjRdrwIDAQABAoIBAQDDGLr5ERdK0UkL
RNurA1LTFGadV4eKTa79xGyIzAWeNEDkjSb0f3xBfm3pwrATOCcMfUcq+UNTI1Ro
ksD+wkZbBE16hYvF+qt/9fe9hi64VlHjE8qgaOTJl4H2WzBOaMcDC6mN5tog9K9L
C7FlaVgTM7Tj4K+KADhmvSfxkyfXQpEmwwOQvmvJzBsQ6pUX0erPnTnCze8jYNBG
vUnxLy5l7Ra1+vAjsdA7nScD+Yjb+zNO/U1+jKNXO2yZu1p3aqJG+tBdQSIzPdWW
dewLXwUBcA6uj95i9AxNF4g7tve4epPwOJbeoPrh1jcr7Xd0qSKuK8iQGoQYGogN
Thn+LbIBAoGBANNyOw6eFe6xxTxxApVkefOMdtjDYzhTqvj44HTMfcy+qvEbws0w
LjWdM5G2XGgsW66Ld22FiVKW4rYM/dKPKpoBbdXMPDFJtf5xfCmAvW2rA4iI5plQ
woRcjJGaVLInZdcyWmbAVWVBVQnJL3d8oXVh9RWNNRwBWK4xnU5tN4BhAoGBAPI2
Bc2KtoqL0oMDgk74KSVOt38zQ2GeX3TulJNrdgp1ZzLtNIkkIw22MH9HXr409oIn
o6O6aE23L3oMOjK41cm7p1WDhiiZmga/7QJxrv4dpAcGjORApBo0S/K4kYTqBAcu
Gaxgn4oBfaShPsJKxNJgiaqs7EQlE8P9cTS64tgPAoGBAJVaA1Lw4McH9CwcGtoQ
7X7VAYFciXHYz1Qq3shBRL5hEvdZR4CNfqZKEoniyGSgqGWih0np37RhdWNny8V1
cH71cXJpXz7lNNKzsCLUl3imKcnAATnb7Hl3saaK3zYzU+Dr5STcx7TMr9dIrul0
M8to1KdTZWcRoGTyEI274U8hAoGAZNflNpyoP6rTbMTLPkHIL8ZEU+tuBHjB2Zdz
uKUnMleLLgLgurCW/6B5NKTsZ1j5wVrroMF9p827MJ9io7edGy7MDqiB9Olu3ZyO
+1OFvjttDZfGlUnsiRR5Aoeh3qroHm0tNz3LbtQMEb0ouhATPlv/NVZl0EF3p0Qg
HAorZDUCgYEAr1ob6yWvqnw/uo9kT1FOGwHx1X0DoOiiDdDwOjRpQtKFpsJuV1c+
TbM3s1CX1dwW5LYUBAAE5951MF3ZLvhSCAEeiYpS88RTgdwTJ1QwdVRvBvM+057l
pAfcaM/uoxbLfdg5Rw17/aPibCr2v+t0cpG3wxo/hI9fiKB2S9REnXU=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID6jCCAtKgAwIBAgIUNJmRmFgHCzRlC4L5soD0FNbuB1gwDQYJKoZIhvcNAQEL
BQAwVDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
B1NlYXR0bGUxEDAOBgNVBAoTB1NvbWVvbmUxDDAKBgNVBAsTA1dXVzAeFw0yMDA1
MjExOTMxMDBaFw0yMTA1MjExOTMxMDBaMGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRAwDgYDVQQKEwdTb21lb25l
MQwwCgYDVQQLEwNXV1cxFTATBgNVBAMTDHNlcnZlci5sb2NhbDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMgOmrdGuQGKWYRuAMS/GiQ9HWQxwH76v/1i
1UYtwKhmJyEHk5HLUpTa/JqlpKJN2Bd5PMGtECr3N9YddGwQz8NJgtTI4JxmnGrn
pTN8ikvWIJgq/nJY6ToEVxZSw7MRCYAXQBgpsH93beDE3Uz7FlIk4hG17YV2aZS9
HmecYXSoLbWqGh2XXNm2BFaENg1CjxKmQgujb9AS51E5j6FyME5sz94ZCkBUa0Y+
CmUC4kbOCaWNtPpy5kXMebE8VNNhrqHNMhK4o7wnpelC/DTc9hZ6UKb/aikbcOhX
ZpFhym+6eid3FU36Y14xaFgOTKEb963J22p/SBA+XgcGuQo0Xa8CAwEAAaOBnDCB
mTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMUStkfqsruTAC3VgIY5FApZdriBMB8G
A1UdIwQYMBaAFPJOSvsV7hOIwUhl6wMXnfguXG7YMBoGA1UdEQQTMBGCCWxvY2Fs
aG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAF7TDTZAgEi4x4x6z4+Zp6pqN
eaPLZaayRJAYp3jGtdv6+f392CkWnhRRlIwf45q+emKwqnnoh4kbPOKGD5i6bRuW
Ite0OcwhxokJebkykG3FHUf9dTHKVeLke1sxIP4FfQu22CdOpGl5V7GwYf9FoIiQ
e5cJW48VlciKY9y9T4QdULXfd3J4KO8Q+6GVVPFUssbr0WfraKpCQZzE65VHyUMs
HOLcttIHEx3R8m/FR+B9aBUIbtIYv62w+WHiXaL74gLXAsnoeU3iB11Ko4U8c2Pr
hTRF7ecpJuz95QNeSgBqIlpKKfWcVMAyebw+W/IAEILsfsrzxX0EpTAc/QicOw==
-----END CERTIFICATE-----
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment