diff --git a/certificates/public-loki-foundation.crt b/certificates/public-loki-foundation.crt new file mode 100644 index 000000000..344a05543 --- /dev/null +++ b/certificates/public-loki-foundation.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEEzCCAvugAwIBAgIUY9RQqbjhsQEkdeSgV9L0os9xZ7AwDQYJKoZIhvcNAQEL +BQAwfDELMAkGA1UEBhMCQVUxETAPBgNVBAgMCFZpY3RvcmlhMRIwEAYDVQQHDAlN +ZWxib3VybmUxJTAjBgNVBAoMHE94ZW4gUHJpdmFjeSBUZWNoIEZvdW5kYXRpb24x +HzAdBgNVBAMMFnB1YmxpYy5sb2tpLmZvdW5kYXRpb24wHhcNMjEwNDA3MDExMDMx +WhcNMjMwNDA3MDExMDMxWjB8MQswCQYDVQQGEwJBVTERMA8GA1UECAwIVmljdG9y +aWExEjAQBgNVBAcMCU1lbGJvdXJuZTElMCMGA1UECgwcT3hlbiBQcml2YWN5IFRl +Y2ggRm91bmRhdGlvbjEfMB0GA1UEAwwWcHVibGljLmxva2kuZm91bmRhdGlvbjCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM5dBJSIR5+VNNUxUOo6FG0e +RmZteRqBt50KXGbOi2A23a6sa57pLFh9Yw3hmlWV+QCL7ipG1X4IC55OStgoesf+ +K65VwEMP6Mtq0sSJS3R5TiuV2ZSRdSZTVjUyRXVe5T4Aw6wXVTAbc/HsyS780tDh +GclfDHhonPhZpmTAnSbfMOS+BfOnBNvDxdto0kVh6k5nrGlkT4ECloulHTQF2lwJ +0D6IOtv9AJplPdg6s2c4dY7durOdvr3NNVfvn5PTeRvbEPqzZur4WUUKIPNGu6mY +PxImqd4eUsL0Vod4aAsTIx4YMmCTi0m9W6zJI6nXcK/6a+iiA3+NTNMzEA9gQhEC +AwEAAaOBjDCBiTAdBgNVHQ4EFgQU/zahokxLvvFUpbnM6z/pwS1KsvwwHwYDVR0j +BBgwFoAU/zahokxLvvFUpbnM6z/pwS1KsvwwDwYDVR0TAQH/BAUwAwEB/zAhBgNV +HREEGjAYghZwdWJsaWMubG9raS5mb3VuZGF0aW9uMBMGA1UdJQQMMAoGCCsGAQUF +BwMBMA0GCSqGSIb3DQEBCwUAA4IBAQBql+JvoqpaYrFFTOuDn08U+pdcd3GM7tbI +zRH5LU+YnIpp9aRheek+2COW8DXsIy/kUngETCMLmX6ZaUj/WdHnTDkB0KTgxSHv +ad3ZznKPKZ26qJOklr+0ZWj4J3jHbisSzql6mqq7R2Kp4ESwzwqxvkbykM5RUnmz +Go/3Ol7bpN/ZVwwEkGfD/5rRHf57E/gZn2pBO+zotlQgr7HKRsIXQ2hIXVQqWmPQ +lvfIwrwAZlfES7BARFnHOpyVQxV8uNcV5K5eXzuVFjHBqvq+BtyGhWkP9yKJCHS9 +OUXxch0rzRsH2C/kRVVhEk0pI3qlFiRC8pCJs98SNE9l69EQtG7I +-----END CERTIFICATE----- diff --git a/certificates/storage-seed-1.crt b/certificates/storage-seed-1.crt new file mode 100644 index 000000000..7360d6fca --- /dev/null +++ b/certificates/storage-seed-1.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEITCCAwmgAwIBAgIUJsox1ZQPK/6iDsCC+MUJfNAlFuYwDQYJKoZIhvcNAQEL +BQAwgYAxCzAJBgNVBAYTAkFVMREwDwYDVQQIDAhWaWN0b3JpYTESMBAGA1UEBwwJ +TWVsYm91cm5lMSUwIwYDVQQKDBxPeGVuIFByaXZhY3kgVGVjaCBGb3VuZGF0aW9u +MSMwIQYDVQQDDBpzdG9yYWdlLnNlZWQxLmxva2kubmV0d29yazAeFw0yMTA0MDcw +MTE5MjZaFw0yMzA0MDcwMTE5MjZaMIGAMQswCQYDVQQGEwJBVTERMA8GA1UECAwI +VmljdG9yaWExEjAQBgNVBAcMCU1lbGJvdXJuZTElMCMGA1UECgwcT3hlbiBQcml2 +YWN5IFRlY2ggRm91bmRhdGlvbjEjMCEGA1UEAwwac3RvcmFnZS5zZWVkMS5sb2tp +Lm5ldHdvcmswggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtWH3Rz8Dd +kEmM7tcBWHrJ/G8drr/+qidboEVYzxpyRjszaDxKXVhx4eBBsAD5RuCWuTuZmM8k +TKEDLtf8xfb5SQ7YNX+346s9NXS5Poy4CIPASiW/QWXgIHFbVdv2hC+cKOP61OLM +OGnOxfig6tQyd6EaCkedpY1DvSa2lPnQSOwC/jXCx6Vboc0zTY5R2bHtNc9hjIFP +F4VClLAQSh2F4R1V9MH5KZMW+CCP6oaJY658W9JYXYRwlLrL2EFOVxHgcxq/6+fw ++axXK9OXJrGZjuA+hiz+L/uAOtE4WuxrSeuNMHSrMtM9QqVn4bBuMJ21mAzfNoMP +OIwgMT9DwUjVAgMBAAGjgZAwgY0wHQYDVR0OBBYEFOubJp9SoXIw+ONiWgkOaW8K +zI/TMB8GA1UdIwQYMBaAFOubJp9SoXIw+ONiWgkOaW8KzI/TMA8GA1UdEwEB/wQF +MAMBAf8wJQYDVR0RBB4wHIIac3RvcmFnZS5zZWVkMS5sb2tpLm5ldHdvcmswEwYD +VR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAIiHNhNrjYvwXVWs +gacx8T/dpqpu9GE3L17LotgQr4R+IYHpNtcmwOTdtWWFfUTr75OCs+c3DqgRKEoj +lnULOsVcalpAGIvW15/fmZWOf66Dpa4+ljDmAc3SOQiD0gGNtqblgI5zG1HF38QP +hjYRhCZ5CVeGOLucvQ8tVVwQvArPFIkBr0jH9jHVgRWEI2MeI3FsU2H93D4TfGln +N4SmmCfYBqygaaZBWkJEt0bYhn8uGHdU9UY9L2FPtfHVKkmFgO7cASGlvXS7B/TT +/8IgbtM3O8mZc2asmdQhGwoAKz93ryyCd8X2UZJg/IwCSCayOlYZWY2fR4OPQmmV +gxJsm+g= +-----END CERTIFICATE----- diff --git a/certificates/storage-seed-3.crt b/certificates/storage-seed-3.crt new file mode 100644 index 000000000..92574b769 --- /dev/null +++ b/certificates/storage-seed-3.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEITCCAwmgAwIBAgIUc486Dy9Y00bUFfDeYmJIgSS5xREwDQYJKoZIhvcNAQEL +BQAwgYAxCzAJBgNVBAYTAkFVMREwDwYDVQQIDAhWaWN0b3JpYTESMBAGA1UEBwwJ +TWVsYm91cm5lMSUwIwYDVQQKDBxPeGVuIFByaXZhY3kgVGVjaCBGb3VuZGF0aW9u +MSMwIQYDVQQDDBpzdG9yYWdlLnNlZWQzLmxva2kubmV0d29yazAeFw0yMTA0MDcw +MTIwNTJaFw0yMzA0MDcwMTIwNTJaMIGAMQswCQYDVQQGEwJBVTERMA8GA1UECAwI +VmljdG9yaWExEjAQBgNVBAcMCU1lbGJvdXJuZTElMCMGA1UECgwcT3hlbiBQcml2 +YWN5IFRlY2ggRm91bmRhdGlvbjEjMCEGA1UEAwwac3RvcmFnZS5zZWVkMy5sb2tp +Lm5ldHdvcmswggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtokMlsFzf +piYeD0EVNikMyvjltpF6fUEde9NOVrTtNTQT6kkDk+/0HF5LYgPaatv6v7fpUQHi +kIwd6F0LTRGeWDFdsaWMdtlR1n/GxLPrOROsE8dcLt6GLavPf9rDabgva93m/JD6 +XW+Ne+MPEwqS8dAmFGhZd0gju6AtKFoSHnIf5pSQN6fSZUF/JQtHLVprAKKWKDiS +ZwmWbmrZR2aofLD/VRpetabajnZlv9EeWloQwvUsw1C1hkAmmtFeeXtg7ePwrOzo +6CnmcUJwOmi+LWqQV4A+58RZPFKaZoC5pzaKd0OYB8eZ8HB1F41UjGJgheX5Cyl4 ++amfF3l8dSq1AgMBAAGjgZAwgY0wHQYDVR0OBBYEFM9VSq4pGydjtX92Beul4+ml +jBKtMB8GA1UdIwQYMBaAFM9VSq4pGydjtX92Beul4+mljBKtMA8GA1UdEwEB/wQF +MAMBAf8wJQYDVR0RBB4wHIIac3RvcmFnZS5zZWVkMy5sb2tpLm5ldHdvcmswEwYD +VR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAAYxmhhkcKE1n6g1 +JqOa3UCBo4EfbqY5+FDZ0FVqv/cwemwVpKLbe6luRIS8poomdPCyMOS45V7wN3H9 +cFpfJ1TW19ydPVKmCXrl29ngmnY1q7YDwE/4qi3VK/UiqDkTHMKWjVPkenOyi8u6 +VVQANXSnKrn6GtigNFjGyD38O+j7AUSXBtXOJczaoF6r6BWgwQZ2WmgjuwvKTWSN +4r8uObERoAQYVaeXfgdr4e9X/JdskBDaLFfoW/rrSozHB4FqVNFW96k+aIUgRa5p +9kv115QcBPCSh9qOyTHij4tswS6SyOFaiKrNC4hgHQXP4QgioKmtsR/2Y+qJ6ddH +6oo+4QU= +-----END CERTIFICATE----- diff --git a/config/default.json b/config/default.json index 029f2a0c0..03ac99195 100644 --- a/config/default.json +++ b/config/default.json @@ -6,16 +6,16 @@ "defaultPoWDifficulty": "1", "seedNodeList": [ { - "ip_url": "http://116.203.53.213/", - "url": "https://storage.seed1.loki.network/" + "ip_url": "http://116.203.53.213:4433/", + "url": "https://storage.seed1.loki.network:4433/" }, { - "ip_url": "http://212.199.114.66/", - "url": "https://storage.seed3.loki.network/" + "ip_url": "http://212.199.114.66:4433/", + "url": "https://storage.seed3.loki.network:4433/" }, { - "ip_url": "http://144.76.164.202/", - "url": "https://public.loki.foundation/" + "ip_url": "http://144.76.164.202:4433/", + "url": "https://public.loki.foundation:4433/" } ], "updatesEnabled": false, diff --git a/package.json b/package.json index 47dc3ad74..9292ef58c 100644 --- a/package.json +++ b/package.json @@ -304,6 +304,7 @@ "debug_log_preload.js", "password_preload.js", "main.js", + "certificates/**", "images/**", "fonts/*", "build/assets", diff --git a/ts/session/snode_api/serviceNodeAPI.ts b/ts/session/snode_api/serviceNodeAPI.ts index 95aa4dfe7..d1a717e92 100644 --- a/ts/session/snode_api/serviceNodeAPI.ts +++ b/ts/session/snode_api/serviceNodeAPI.ts @@ -1,5 +1,14 @@ // we don't throw or catch here import { default as insecureNodeFetch } from 'node-fetch'; +import https from 'https'; +import crypto from 'crypto'; + +import fs from 'fs'; +import path from 'path'; +import tls from 'tls'; +import Electron from 'electron'; + +const { remote } = Electron; import { snodeRpc } from './lokiRpc'; import { @@ -78,6 +87,93 @@ export async function getVersion( } } +const sha256 = (s: string) => { + return crypto + .createHash('sha256') + .update(s) + .digest('base64'); +}; + +const getSslAgentForSeedNode = (seedNodeHost: string) => { + let filePrefix = ''; + let pubkey256 = ''; + let cert256 = ''; + + switch (seedNodeHost) { + case 'storage.seed1.loki.network': + filePrefix = 'storage-seed-1'; + pubkey256 = 'JOsnIcAanVbgECNA8lHtC8f/cqN9m8EP7jKT6XCjeL8='; + cert256 = + '6E:2B:AC:F3:6E:C1:FF:FF:24:F3:CA:92:C6:94:81:B4:82:43:DF:C7:C6:03:98:B8:F5:6B:7D:30:7B:16:C1:CB'; + break; + case 'storage.seed3.loki.network': + filePrefix = 'storage-seed-3'; + pubkey256 = 'mMmZD3lG4Fi7nTC/EWzRVaU3bbCLsH6Ds2FHSTpo0Rk='; + cert256 = + '24:13:4C:0A:03:D8:42:A6:09:DE:35:76:F4:BD:FB:11:60:DB:F9:88:9F:98:46:B7:60:A6:60:0C:4C:CF:60:72'; + + break; + case 'public.loki.foundation': + filePrefix = 'public-loki-foundation'; + pubkey256 = 'W+Zv52qlcm1BbdpJzFwxZrE7kfmEboq7h3Dp/+Q3RPg='; + cert256 = + '40:E4:67:7D:18:6B:4D:08:8D:E9:D5:47:52:25:B8:28:E0:D3:63:99:9B:38:46:7D:92:19:5B:61:B9:AE:0E:EA'; + + break; + + default: + throw new Error(`Unknown seed node: ${seedNodeHost}`); + } + // tslint:disable: non-literal-fs-path + // read the cert each time. We only run this request once for each seed node nevertheless. + const appPath = remote.app.getAppPath(); + const crt = fs.readFileSync( + path.join(appPath, `/certificates/${filePrefix}.crt`), + 'utf-8' + ); + // debugger; + const sslOptions = { + // as the seed nodes are using a self signed certificate, we have to provide it here. + ca: crt, + // we might need to selectively disable that for tests on swarm-testing or so. + // we have to reject them, otherwise our errors returned in the checkServerIdentity are simply not making the call fail. + // so in production, rejectUnauthorized must be true. + rejectUnauthorized: true, + keepAlive: false, + checkServerIdentity: (host: string, cert: any) => { + // Make sure the certificate is issued to the host we are connected to + const err = tls.checkServerIdentity(host, cert); + if (err) { + return err; + } + + // we might need to selectively disable that for tests on swarm-testing or so. + + // Pin the public key, similar to HPKP pin-sha25 pinning + if (sha256(cert.pubkey) !== pubkey256) { + const msg = + 'Certificate verification error: ' + + `The public key of '${cert.subject.CN}' ` + + 'does not match our pinned fingerprint'; + return new Error(msg); + } + + // Pin the exact certificate, rather than the pub key + if (cert.fingerprint256 !== cert256) { + const msg = + 'Certificate verification error: ' + + `The certificate of '${cert.subject.CN}' ` + + 'does not match our pinned fingerprint'; + return new Error(msg); + } + return undefined; + }, + }; + + // we're creating a new Agent that will now use the certs we have configured + return new https.Agent(sslOptions); +}; + export async function getSnodesFromSeedUrl(urlObj: URL): Promise> { const { log } = window; @@ -103,11 +199,14 @@ export async function getSnodesFromSeedUrl(urlObj: URL): Promise> { method: 'get_n_service_nodes', params, }; + const sslAgent = getSslAgentForSeedNode(urlObj.hostname); const fetchOptions = { method: 'POST', timeout: 10000, body: JSON.stringify(body), + + agent: sslAgent, }; window.log.info('insecureNodeFetch => plaintext for getSnodesFromSeedUrl'); diff --git a/ts/session/snode_api/snodePool.ts b/ts/session/snode_api/snodePool.ts index 4bd6a21c3..d4bec192b 100644 --- a/ts/session/snode_api/snodePool.ts +++ b/ts/session/snode_api/snodePool.ts @@ -1,22 +1,18 @@ +import semver from 'semver'; +import _ from 'lodash'; + import { abortableIterator, allowOnlyOneAtATime, } from '../../../js/modules/loki_primitives'; -import { - getSnodesFromSeedUrl, - getVersion, - requestSnodesForPubkey, -} from './serviceNodeAPI'; +import { getSnodesFromSeedUrl, requestSnodesForPubkey } from './serviceNodeAPI'; import { getSwarmNodesForPubkey, updateSwarmNodesForPubkey, } from '../../../ts/data/data'; -import semver from 'semver'; -import _ from 'lodash'; - export type SnodeEdKey = string; const MIN_NODES = 3; @@ -60,6 +56,7 @@ async function tryGetSnodeListFromLokidSeednode( let snodes = []; try { const tryUrl = new URL(seedNode.url); + snodes = await getSnodesFromSeedUrl(tryUrl); // throw before clearing the lock, so the retries can kick in if (snodes.length === 0) {