pin certificate for seed nodes
This commit is contained in:
parent
a010630775
commit
47026b8d5b
|
@ -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-----
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -6,16 +6,16 @@
|
||||||
"defaultPoWDifficulty": "1",
|
"defaultPoWDifficulty": "1",
|
||||||
"seedNodeList": [
|
"seedNodeList": [
|
||||||
{
|
{
|
||||||
"ip_url": "http://116.203.53.213/",
|
"ip_url": "http://116.203.53.213:4433/",
|
||||||
"url": "https://storage.seed1.loki.network/"
|
"url": "https://storage.seed1.loki.network:4433/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ip_url": "http://212.199.114.66/",
|
"ip_url": "http://212.199.114.66:4433/",
|
||||||
"url": "https://storage.seed3.loki.network/"
|
"url": "https://storage.seed3.loki.network:4433/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ip_url": "http://144.76.164.202/",
|
"ip_url": "http://144.76.164.202:4433/",
|
||||||
"url": "https://public.loki.foundation/"
|
"url": "https://public.loki.foundation:4433/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updatesEnabled": false,
|
"updatesEnabled": false,
|
||||||
|
|
|
@ -304,6 +304,7 @@
|
||||||
"debug_log_preload.js",
|
"debug_log_preload.js",
|
||||||
"password_preload.js",
|
"password_preload.js",
|
||||||
"main.js",
|
"main.js",
|
||||||
|
"certificates/**",
|
||||||
"images/**",
|
"images/**",
|
||||||
"fonts/*",
|
"fonts/*",
|
||||||
"build/assets",
|
"build/assets",
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
// we don't throw or catch here
|
// we don't throw or catch here
|
||||||
import { default as insecureNodeFetch } from 'node-fetch';
|
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 { snodeRpc } from './lokiRpc';
|
||||||
import {
|
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<Array<any>> {
|
export async function getSnodesFromSeedUrl(urlObj: URL): Promise<Array<any>> {
|
||||||
const { log } = window;
|
const { log } = window;
|
||||||
|
|
||||||
|
@ -103,11 +199,14 @@ export async function getSnodesFromSeedUrl(urlObj: URL): Promise<Array<any>> {
|
||||||
method: 'get_n_service_nodes',
|
method: 'get_n_service_nodes',
|
||||||
params,
|
params,
|
||||||
};
|
};
|
||||||
|
const sslAgent = getSslAgentForSeedNode(urlObj.hostname);
|
||||||
|
|
||||||
const fetchOptions = {
|
const fetchOptions = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
|
|
||||||
|
agent: sslAgent,
|
||||||
};
|
};
|
||||||
window.log.info('insecureNodeFetch => plaintext for getSnodesFromSeedUrl');
|
window.log.info('insecureNodeFetch => plaintext for getSnodesFromSeedUrl');
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
|
import semver from 'semver';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
abortableIterator,
|
abortableIterator,
|
||||||
allowOnlyOneAtATime,
|
allowOnlyOneAtATime,
|
||||||
} from '../../../js/modules/loki_primitives';
|
} from '../../../js/modules/loki_primitives';
|
||||||
|
|
||||||
import {
|
import { getSnodesFromSeedUrl, requestSnodesForPubkey } from './serviceNodeAPI';
|
||||||
getSnodesFromSeedUrl,
|
|
||||||
getVersion,
|
|
||||||
requestSnodesForPubkey,
|
|
||||||
} from './serviceNodeAPI';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getSwarmNodesForPubkey,
|
getSwarmNodesForPubkey,
|
||||||
updateSwarmNodesForPubkey,
|
updateSwarmNodesForPubkey,
|
||||||
} from '../../../ts/data/data';
|
} from '../../../ts/data/data';
|
||||||
|
|
||||||
import semver from 'semver';
|
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
export type SnodeEdKey = string;
|
export type SnodeEdKey = string;
|
||||||
|
|
||||||
const MIN_NODES = 3;
|
const MIN_NODES = 3;
|
||||||
|
@ -60,6 +56,7 @@ async function tryGetSnodeListFromLokidSeednode(
|
||||||
let snodes = [];
|
let snodes = [];
|
||||||
try {
|
try {
|
||||||
const tryUrl = new URL(seedNode.url);
|
const tryUrl = new URL(seedNode.url);
|
||||||
|
|
||||||
snodes = await getSnodesFromSeedUrl(tryUrl);
|
snodes = await getSnodesFromSeedUrl(tryUrl);
|
||||||
// throw before clearing the lock, so the retries can kick in
|
// throw before clearing the lock, so the retries can kick in
|
||||||
if (snodes.length === 0) {
|
if (snodes.length === 0) {
|
||||||
|
|
Loading…
Reference in New Issue