@libp2p/tls 0.0.0 → 1.0.0-0c7bbbb07

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * @packageDocumentation
3
3
  *
4
- * A connection encrypter that does no connection encryption.
5
- *
6
- * This should not be used in production should be used for research purposes only.
4
+ * Implements the spec at https://github.com/libp2p/specs/blob/master/tls/tls.md
7
5
  *
8
6
  * @example
9
7
  *
@@ -20,6 +18,7 @@
20
18
  * ```
21
19
  */
22
20
  import type { ComponentLogger, ConnectionEncrypter } from '@libp2p/interface';
21
+ export declare const PROTOCOL = "/tls/1.0.0";
23
22
  export interface TLSComponents {
24
23
  logger: ComponentLogger;
25
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AASH,OAAO,KAAK,EAAE,eAAe,EAAuB,mBAAmB,EAA6B,MAAM,mBAAmB,CAAA;AAM7H,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AA+ED,wBAAgB,GAAG,CAAE,IAAI,CAAC,EAAE,OAAO,GAAG,CAAC,UAAU,EAAE,aAAa,KAAK,mBAAmB,CAEvF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAE7E,eAAO,MAAM,QAAQ,eAAe,CAAA;AAEpC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAgB,GAAG,CAAE,IAAI,CAAC,EAAE,OAAO,GAAG,CAAC,UAAU,EAAE,aAAa,KAAK,mBAAmB,CAEvF"}
package/dist/src/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * @packageDocumentation
3
3
  *
4
- * A connection encrypter that does no connection encryption.
5
- *
6
- * This should not be used in production should be used for research purposes only.
4
+ * Implements the spec at https://github.com/libp2p/specs/blob/master/tls/tls.md
7
5
  *
8
6
  * @example
9
7
  *
@@ -19,81 +17,9 @@
19
17
  * })
20
18
  * ```
21
19
  */
22
- import { TLSSocket, connect } from 'node:tls';
23
- import { UnexpectedPeerError } from '@libp2p/interface';
24
- // @ts-expect-error no types
25
- import itToStream from 'it-to-stream';
26
- // @ts-expect-error no types
27
- import streamToIt from 'stream-to-it';
28
- import { generateCertificate, verifyPeerCertificate } from './utils.js';
29
- const PROTOCOL = '/tls/1.0.0';
30
- class TLS {
31
- protocol = PROTOCOL;
32
- // private readonly log: Logger
33
- // private readonly timeout: number
34
- // constructor (components: TLSComponents, init: TLSInit = {}) {
35
- // this.log = components.logger.forComponent('libp2p:tls')
36
- // this.timeout = init.timeout ?? 1000
37
- // }
38
- async secureInbound(localId, conn, remoteId) {
39
- return this._encrypt(localId, conn, false, remoteId);
40
- }
41
- async secureOutbound(localId, conn, remoteId) {
42
- return this._encrypt(localId, conn, true, remoteId);
43
- }
44
- /**
45
- * Encrypt connection
46
- */
47
- async _encrypt(localId, conn, isServer, remoteId) {
48
- const opts = {
49
- ...await generateCertificate(localId),
50
- isServer,
51
- requestCert: true,
52
- // accept self-signed certificates
53
- rejectUnauthorized: false,
54
- // require TLS 1.3 or later
55
- minVersion: 'TLSv1.3'
56
- };
57
- let socket;
58
- if (isServer) {
59
- socket = new TLSSocket(itToStream.duplex(conn), opts);
60
- }
61
- else {
62
- socket = connect({
63
- socket: itToStream.duplex(conn),
64
- ...opts
65
- });
66
- }
67
- return new Promise((resolve, reject) => {
68
- function verifyRemote() {
69
- const remote = socket.getPeerCertificate();
70
- verifyPeerCertificate(remote.raw)
71
- .then(remotePeer => {
72
- if (remoteId?.equals(remotePeer) === false) {
73
- throw new UnexpectedPeerError();
74
- }
75
- const outputStream = streamToIt.duplex(socket);
76
- conn.source = outputStream.source;
77
- conn.sink = outputStream.sink;
78
- resolve({
79
- remotePeer,
80
- conn
81
- });
82
- })
83
- .catch(err => {
84
- reject(err);
85
- });
86
- }
87
- socket.on('error', err => {
88
- reject(err);
89
- });
90
- socket.on('secure', (evt) => {
91
- verifyRemote();
92
- });
93
- });
94
- }
95
- }
20
+ import { TLS } from './tls.js';
21
+ export const PROTOCOL = '/tls/1.0.0';
96
22
  export function tls(init) {
97
- return (components) => new TLS();
23
+ return (components) => new TLS(components, init);
98
24
  }
99
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAG9B,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAAA;AAcpC,MAAM,UAAU,GAAG,CAAE,IAAc;IACjC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;AAClD,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Implements the spec at https://github.com/libp2p/specs/blob/master/tls/tls.md
5
+ *
6
+ * @example
7
+ *
8
+ * ```typescript
9
+ * import { createLibp2p } from 'libp2p'
10
+ * import { tls } from '@libp2p/tls'
11
+ *
12
+ * const node = await createLibp2p({
13
+ * // ...other options
14
+ * connectionEncryption: [
15
+ * tls()
16
+ * ]
17
+ * })
18
+ * ```
19
+ */
20
+ import type { TLSComponents, TLSInit } from './index.js';
21
+ import type { MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId } from '@libp2p/interface';
22
+ import type { Duplex } from 'it-stream-types';
23
+ import type { Uint8ArrayList } from 'uint8arraylist';
24
+ export declare class TLS implements ConnectionEncrypter {
25
+ protocol: string;
26
+ private readonly log;
27
+ private readonly timeout;
28
+ constructor(components: TLSComponents, init?: TLSInit);
29
+ secureInbound<Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection>(localId: PeerId, conn: Stream, remoteId?: PeerId): Promise<SecuredConnection<Stream>>;
30
+ secureOutbound<Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection>(localId: PeerId, conn: Stream, remoteId?: PeerId): Promise<SecuredConnection<Stream>>;
31
+ /**
32
+ * Encrypt connection
33
+ */
34
+ _encrypt<Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection>(localId: PeerId, conn: Stream, isServer: boolean, remoteId?: PeerId): Promise<SecuredConnection<Stream>>;
35
+ }
36
+ //# sourceMappingURL=tls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls.d.ts","sourceRoot":"","sources":["../../src/tls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,EAAU,MAAM,mBAAmB,CAAA;AACpH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,qBAAa,GAAI,YAAW,mBAAmB;IACtC,QAAQ,EAAE,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;gBAEnB,UAAU,EAAE,aAAa,EAAE,IAAI,GAAE,OAAY;IAKpD,aAAa,CAAE,MAAM,SAAS,MAAM,CAAC,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,CAAC,GAAG,mBAAmB,EAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAI/L,cAAc,CAAE,MAAM,SAAS,MAAM,CAAC,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,CAAC,GAAG,mBAAmB,EAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAItM;;OAEG;IACG,QAAQ,CAAE,MAAM,SAAS,MAAM,CAAC,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,CAAC,GAAG,mBAAmB,EAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;CAgEpN"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Implements the spec at https://github.com/libp2p/specs/blob/master/tls/tls.md
5
+ *
6
+ * @example
7
+ *
8
+ * ```typescript
9
+ * import { createLibp2p } from 'libp2p'
10
+ * import { tls } from '@libp2p/tls'
11
+ *
12
+ * const node = await createLibp2p({
13
+ * // ...other options
14
+ * connectionEncryption: [
15
+ * tls()
16
+ * ]
17
+ * })
18
+ * ```
19
+ */
20
+ import { TLSSocket, connect } from 'node:tls';
21
+ import { CodeError } from '@libp2p/interface';
22
+ import { generateCertificate, verifyPeerCertificate, itToStream, streamToIt } from './utils.js';
23
+ import { PROTOCOL } from './index.js';
24
+ export class TLS {
25
+ protocol = PROTOCOL;
26
+ log;
27
+ timeout;
28
+ constructor(components, init = {}) {
29
+ this.log = components.logger.forComponent('libp2p:tls');
30
+ this.timeout = init.timeout ?? 1000;
31
+ }
32
+ async secureInbound(localId, conn, remoteId) {
33
+ return this._encrypt(localId, conn, false, remoteId);
34
+ }
35
+ async secureOutbound(localId, conn, remoteId) {
36
+ return this._encrypt(localId, conn, true, remoteId);
37
+ }
38
+ /**
39
+ * Encrypt connection
40
+ */
41
+ async _encrypt(localId, conn, isServer, remoteId) {
42
+ const opts = {
43
+ ...await generateCertificate(localId),
44
+ isServer,
45
+ // require TLS 1.3 or later
46
+ minVersion: 'TLSv1.3',
47
+ maxVersion: 'TLSv1.3',
48
+ // accept self-signed certificates
49
+ rejectUnauthorized: false
50
+ };
51
+ let socket;
52
+ if (isServer) {
53
+ socket = new TLSSocket(itToStream(conn), {
54
+ ...opts,
55
+ // require clients to send certificates
56
+ requestCert: true
57
+ });
58
+ }
59
+ else {
60
+ socket = connect({
61
+ socket: itToStream(conn),
62
+ ...opts
63
+ });
64
+ }
65
+ return new Promise((resolve, reject) => {
66
+ const abortTimeout = setTimeout(() => {
67
+ socket.destroy(new CodeError('Handshake timeout', 'ERR_HANDSHAKE_TIMEOUT'));
68
+ }, this.timeout);
69
+ const verifyRemote = () => {
70
+ const remote = socket.getPeerCertificate();
71
+ verifyPeerCertificate(remote.raw, remoteId, this.log)
72
+ .then(remotePeer => {
73
+ this.log('remote certificate ok, remote peer %p', remotePeer);
74
+ resolve({
75
+ remotePeer,
76
+ conn: {
77
+ ...conn,
78
+ ...streamToIt(socket)
79
+ }
80
+ });
81
+ })
82
+ .catch(err => {
83
+ reject(err);
84
+ })
85
+ .finally(() => {
86
+ clearTimeout(abortTimeout);
87
+ });
88
+ };
89
+ socket.on('error', err => {
90
+ reject(err);
91
+ clearTimeout(abortTimeout);
92
+ });
93
+ socket.on('secure', (evt) => {
94
+ this.log('verifying remote certificate');
95
+ verifyRemote();
96
+ });
97
+ });
98
+ }
99
+ }
100
+ //# sourceMappingURL=tls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls.js","sourceRoot":"","sources":["../../src/tls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,SAAS,EAAyB,OAAO,EAAE,MAAM,UAAU,CAAA;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC/F,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAMrC,MAAM,OAAO,GAAG;IACP,QAAQ,GAAW,QAAQ,CAAA;IACjB,GAAG,CAAQ;IACX,OAAO,CAAQ;IAEhC,YAAa,UAAyB,EAAE,OAAgB,EAAE;QACxD,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAA;QACvD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAA;IACrC,CAAC;IAED,KAAK,CAAC,aAAa,CAA6F,OAAe,EAAE,IAAY,EAAE,QAAiB;QAC9J,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;IACtD,CAAC;IAED,KAAK,CAAC,cAAc,CAA6F,OAAe,EAAE,IAAY,EAAE,QAAiB;QAC/J,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;IACrD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAA6F,OAAe,EAAE,IAAY,EAAE,QAAiB,EAAE,QAAiB;QAC5K,MAAM,IAAI,GAAqB;YAC7B,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC;YACrC,QAAQ;YACR,2BAA2B;YAC3B,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,SAAS;YACrB,kCAAkC;YAClC,kBAAkB,EAAE,KAAK;SAC1B,CAAA;QAED,IAAI,MAAiB,CAAA;QAErB,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;gBACvC,GAAG,IAAI;gBACP,uCAAuC;gBACvC,WAAW,EAAE,IAAI;aAClB,CAAC,CAAA;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,OAAO,CAAC;gBACf,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC;gBACxB,GAAG,IAAI;aACR,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE;gBACnC,MAAM,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,mBAAmB,EAAE,uBAAuB,CAAC,CAAC,CAAA;YAC7E,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;YAEhB,MAAM,YAAY,GAAG,GAAS,EAAE;gBAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,EAAE,CAAA;gBAE1C,qBAAqB,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC;qBAClD,IAAI,CAAC,UAAU,CAAC,EAAE;oBACjB,IAAI,CAAC,GAAG,CAAC,uCAAuC,EAAE,UAAU,CAAC,CAAA;oBAE7D,OAAO,CAAC;wBACN,UAAU;wBACV,IAAI,EAAE;4BACJ,GAAG,IAAI;4BACP,GAAG,UAAU,CAAC,MAAM,CAAC;yBACtB;qBACF,CAAC,CAAA;gBACJ,CAAC,CAAC;qBACD,KAAK,CAAC,GAAG,CAAC,EAAE;oBACX,MAAM,CAAC,GAAG,CAAC,CAAA;gBACb,CAAC,CAAC;qBACD,OAAO,CAAC,GAAG,EAAE;oBACZ,YAAY,CAAC,YAAY,CAAC,CAAA;gBAC5B,CAAC,CAAC,CAAA;YACN,CAAC,CAAA;YAED,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;gBACvB,MAAM,CAAC,GAAG,CAAC,CAAA;gBACX,YAAY,CAAC,YAAY,CAAC,CAAA;YAC5B,CAAC,CAAC,CAAA;YACF,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC1B,IAAI,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;gBACxC,YAAY,EAAE,CAAA;YAChB,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -1,5 +1,9 @@
1
- import type { PeerId } from '@libp2p/interface';
2
- export declare function verifyPeerCertificate(rawCertificate: Uint8Array): Promise<PeerId>;
1
+ /// <reference types="node" />
2
+ import { Duplex as DuplexStream } from 'node:stream';
3
+ import type { PeerId, Logger } from '@libp2p/interface';
4
+ import type { Duplex } from 'it-stream-types';
5
+ import type { Uint8ArrayList } from 'uint8arraylist';
6
+ export declare function verifyPeerCertificate(rawCertificate: Uint8Array, expectedPeerId?: PeerId, log?: Logger): Promise<PeerId>;
3
7
  export declare function generateCertificate(peerId: PeerId): Promise<{
4
8
  cert: string;
5
9
  key: string;
@@ -8,4 +12,6 @@ export declare function generateCertificate(peerId: PeerId): Promise<{
8
12
  * @see https://github.com/libp2p/specs/blob/master/tls/tls.md#libp2p-public-key-extension
9
13
  */
10
14
  export declare function encodeSignatureData(certPublicKey: ArrayBuffer): Uint8Array;
15
+ export declare function itToStream(conn: Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>>): DuplexStream;
16
+ export declare function streamToIt(stream: DuplexStream): Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>>;
11
17
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,MAAM,EAAgC,MAAM,mBAAmB,CAAA;AAY7E,wBAAsB,qBAAqB,CAAE,cAAc,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmDxF;AAED,wBAAsB,mBAAmB,CAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA8EjG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAE,aAAa,EAAE,WAAW,GAAG,UAAU,CAQ3E"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,aAAa,CAAA;AAcpD,OAAO,KAAK,EAAE,MAAM,EAAgC,MAAM,EAAE,MAAM,mBAAmB,CAAA;AACrF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAYpD,wBAAsB,qBAAqB,CAAE,cAAc,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0E/H;AAED,wBAAsB,mBAAmB,CAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA8EjG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAE,aAAa,EAAE,WAAW,GAAG,UAAU,CAQ3E;AAmBD,wBAAgB,UAAU,CAAE,IAAI,EAAE,MAAM,CAAC,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,CAAC,GAAG,YAAY,CAgCnG;AAED,wBAAgB,UAAU,CAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,CAAC,CA+CrG"}
package/dist/src/utils.js CHANGED
@@ -1,11 +1,13 @@
1
+ import { Duplex as DuplexStream } from 'node:stream';
1
2
  import { Ed25519PublicKey, Secp256k1PublicKey, marshalPublicKey, supportedKeys, unmarshalPrivateKey, unmarshalPublicKey } from '@libp2p/crypto/keys';
2
- import { CodeError, InvalidCryptoExchangeError } from '@libp2p/interface';
3
+ import { CodeError, InvalidCryptoExchangeError, UnexpectedPeerError } from '@libp2p/interface';
3
4
  import { peerIdFromKeys } from '@libp2p/peer-id';
4
5
  import { AsnConvert } from '@peculiar/asn1-schema';
5
6
  import * as asn1X509 from '@peculiar/asn1-x509';
6
7
  import { Crypto } from '@peculiar/webcrypto';
7
8
  import * as x509 from '@peculiar/x509';
8
9
  import * as asn1js from 'asn1js';
10
+ import { pushable } from 'it-pushable';
9
11
  import { concat as uint8ArrayConcat } from 'uint8arrays/concat';
10
12
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
11
13
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
@@ -18,48 +20,67 @@ const CERT_PREFIX = 'libp2p-tls-handshake:';
18
20
  const CERT_VALIDITY_PERIOD_FROM = 60 * 60 * 1000; // ~1 hour
19
21
  // https://github.com/libp2p/go-libp2p/blob/28c0f6ab32cd69e4b18e9e4b550ef6ce059a9d1a/p2p/security/tls/crypto.go#L24C28-L24C44
20
22
  const CERT_VALIDITY_PERIOD_TO = 100 * 365 * 24 * 60 * 60 * 1000; // ~100 years
21
- export async function verifyPeerCertificate(rawCertificate) {
23
+ export async function verifyPeerCertificate(rawCertificate, expectedPeerId, log) {
22
24
  const now = Date.now();
23
25
  const x509Cert = new x509.X509Certificate(rawCertificate);
24
26
  if (x509Cert.notBefore.getTime() > now) {
27
+ log?.error('the certificate was not valid yet');
25
28
  throw new CodeError('The certificate is not valid yet', 'ERR_INVALID_CERTIFICATE');
26
29
  }
27
30
  if (x509Cert.notAfter.getTime() < now) {
31
+ log?.error('the certificate has expired');
28
32
  throw new CodeError('The certificate has expired', 'ERR_INVALID_CERTIFICATE');
29
33
  }
30
- // TODO: assert chain is only one certificate long
34
+ const certSignatureValid = await x509Cert.verify();
35
+ if (!certSignatureValid) {
36
+ log?.error('certificate self signature was invalid');
37
+ throw new InvalidCryptoExchangeError('Invalid certificate self signature');
38
+ }
39
+ const certIsSelfSigned = await x509Cert.isSelfSigned();
40
+ if (!certIsSelfSigned) {
41
+ log?.error('certificate must be self signed');
42
+ throw new InvalidCryptoExchangeError('Certificate must be self signed');
43
+ }
31
44
  const libp2pPublicKeyExtension = x509Cert.extensions[0];
32
45
  if (libp2pPublicKeyExtension == null || libp2pPublicKeyExtension.type !== LIBP2P_PUBLIC_KEY_EXTENSION) {
46
+ log?.error('the certificate did not include the libp2p public key extension');
33
47
  throw new CodeError('The certificate did not include the libp2p public key extension', 'ERR_INVALID_CERTIFICATE');
34
48
  }
35
49
  const { result: libp2pKeySequence } = asn1js.fromBER(libp2pPublicKeyExtension.value);
36
50
  // @ts-expect-error deep chain
37
51
  const remotePeerIdPb = libp2pKeySequence.valueBlock.value[0].valueBlock.valueHex;
38
52
  const marshalledPeerId = new Uint8Array(remotePeerIdPb, 0, remotePeerIdPb.byteLength);
39
- const remotePeerId = PublicKey.decode(marshalledPeerId);
40
- const remotePeerIdData = remotePeerId.data ?? new Uint8Array(0);
41
- let remotePublicKey;
42
- if (remotePeerId.type === KeyType.Ed25519) {
43
- remotePublicKey = new Ed25519PublicKey(remotePeerIdData);
53
+ const remotePublicKey = PublicKey.decode(marshalledPeerId);
54
+ const remotePublicKeyData = remotePublicKey.data ?? new Uint8Array(0);
55
+ let remoteLibp2pPublicKey;
56
+ if (remotePublicKey.type === KeyType.Ed25519) {
57
+ remoteLibp2pPublicKey = new Ed25519PublicKey(remotePublicKeyData);
44
58
  }
45
- else if (remotePeerId.type === KeyType.Secp256k1) {
46
- remotePublicKey = new Secp256k1PublicKey(remotePeerIdData);
59
+ else if (remotePublicKey.type === KeyType.Secp256k1) {
60
+ remoteLibp2pPublicKey = new Secp256k1PublicKey(remotePublicKeyData);
47
61
  }
48
- else if (remotePeerId.type === KeyType.RSA) {
49
- remotePublicKey = supportedKeys.rsa.unmarshalRsaPublicKey(remotePeerIdData);
62
+ else if (remotePublicKey.type === KeyType.RSA) {
63
+ remoteLibp2pPublicKey = supportedKeys.rsa.unmarshalRsaPublicKey(remotePublicKeyData);
50
64
  }
51
65
  else {
52
- throw new Error('Unknown or unsupported key type');
66
+ log?.error('unknown or unsupported key type', remotePublicKey.type);
67
+ throw new InvalidCryptoExchangeError('Unknown or unsupported key type');
53
68
  }
54
69
  // @ts-expect-error deep chain
55
70
  const remoteSignature = libp2pKeySequence.valueBlock.value[1].valueBlock.valueHex;
56
71
  const dataToVerify = encodeSignatureData(x509Cert.publicKey.rawData);
57
- const result = await remotePublicKey.verify(dataToVerify, new Uint8Array(remoteSignature, 0, remoteSignature.byteLength));
72
+ const result = await remoteLibp2pPublicKey.verify(dataToVerify, new Uint8Array(remoteSignature, 0, remoteSignature.byteLength));
58
73
  if (!result) {
59
- throw new Error('Could not verify signature');
74
+ log?.error('invalid libp2p signature');
75
+ throw new InvalidCryptoExchangeError('Could not verify signature');
76
+ }
77
+ const marshalled = marshalPublicKey(remoteLibp2pPublicKey);
78
+ const remotePeerId = await peerIdFromKeys(marshalled);
79
+ if (expectedPeerId?.equals(remotePeerId) === false) {
80
+ log?.error('invalid peer id');
81
+ throw new UnexpectedPeerError();
60
82
  }
61
- const marshalled = marshalPublicKey(remotePublicKey);
62
- return peerIdFromKeys(marshalled);
83
+ return remotePeerId;
63
84
  }
64
85
  export async function generateCertificate(peerId) {
65
86
  const now = Date.now();
@@ -154,4 +175,100 @@ function formatAsPem(str) {
154
175
  finalString = finalString + '-----END PRIVATE KEY-----';
155
176
  return finalString;
156
177
  }
178
+ export function itToStream(conn) {
179
+ const output = pushable();
180
+ const iterator = conn.source[Symbol.asyncIterator]();
181
+ const stream = new DuplexStream({
182
+ autoDestroy: false,
183
+ allowHalfOpen: true,
184
+ write(chunk, encoding, callback) {
185
+ output.push(chunk);
186
+ callback();
187
+ },
188
+ read() {
189
+ iterator.next()
190
+ .then(result => {
191
+ if (result.done === true) {
192
+ this.push(null);
193
+ }
194
+ else {
195
+ this.push(result.value);
196
+ }
197
+ }, (err) => {
198
+ this.destroy(err);
199
+ });
200
+ }
201
+ });
202
+ // @ts-expect-error return type of sink is unknown
203
+ conn.sink(output)
204
+ .catch((err) => {
205
+ stream.destroy(err);
206
+ });
207
+ return stream;
208
+ }
209
+ export function streamToIt(stream) {
210
+ const output = {
211
+ source: (async function* () {
212
+ const output = pushable();
213
+ stream.addListener('data', (buf) => {
214
+ output.push(buf.subarray());
215
+ });
216
+ // both ends closed
217
+ stream.addListener('close', () => {
218
+ output.end();
219
+ });
220
+ stream.addListener('error', (err) => {
221
+ output.end(err);
222
+ });
223
+ // just writable end closed
224
+ stream.addListener('finish', () => {
225
+ output.end();
226
+ });
227
+ try {
228
+ yield* output;
229
+ }
230
+ catch (err) {
231
+ stream.destroy(err);
232
+ throw err;
233
+ }
234
+ })(),
235
+ sink: async (source) => {
236
+ try {
237
+ for await (const buf of source) {
238
+ const sendMore = stream.write(buf.subarray());
239
+ if (!sendMore) {
240
+ await waitForBackpressure(stream);
241
+ }
242
+ }
243
+ // close writable end
244
+ stream.end();
245
+ }
246
+ catch (err) {
247
+ stream.destroy(err);
248
+ throw err;
249
+ }
250
+ }
251
+ };
252
+ return output;
253
+ }
254
+ async function waitForBackpressure(stream) {
255
+ await new Promise((resolve, reject) => {
256
+ const continueListener = () => {
257
+ cleanUp();
258
+ resolve();
259
+ };
260
+ const stopListener = (err) => {
261
+ cleanUp();
262
+ reject(err ?? new Error('Stream ended'));
263
+ };
264
+ const cleanUp = () => {
265
+ stream.removeListener('drain', continueListener);
266
+ stream.removeListener('end', stopListener);
267
+ stream.removeListener('error', stopListener);
268
+ };
269
+ stream.addListener('drain', continueListener);
270
+ stream.addListener('end', stopListener);
271
+ stream.addListener('error', stopListener);
272
+ });
273
+ }
157
274
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@libp2p/tls",
3
- "version": "0.0.0",
3
+ "version": "1.0.0-0c7bbbb07",
4
4
  "description": "A connection encrypter that uses TLS 1.3",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/connection-encrypter-tls#readme",
@@ -11,6 +11,10 @@
11
11
  "bugs": {
12
12
  "url": "https://github.com/libp2p/js-libp2p/issues"
13
13
  },
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "provenance": true
17
+ },
14
18
  "type": "module",
15
19
  "types": "./dist/src/index.d.ts",
16
20
  "files": [
@@ -43,28 +47,27 @@
43
47
  "dep-check": "aegir dep-check"
44
48
  },
45
49
  "dependencies": {
46
- "@libp2p/crypto": "^4.0.1",
47
- "@libp2p/interface": "^1.1.2",
48
- "@libp2p/peer-id": "^4.0.5",
50
+ "@libp2p/crypto": "4.0.2-0c7bbbb07",
51
+ "@libp2p/interface": "1.1.3-0c7bbbb07",
52
+ "@libp2p/peer-id": "4.0.6-0c7bbbb07",
49
53
  "@peculiar/asn1-schema": "^2.3.8",
50
54
  "@peculiar/asn1-x509": "^2.3.8",
51
55
  "@peculiar/webcrypto": "^1.4.5",
52
- "@peculiar/x509": "^1.9.6",
56
+ "@peculiar/x509": "^1.9.7",
53
57
  "asn1js": "^3.0.5",
58
+ "it-pushable": "^3.2.3",
54
59
  "it-stream-types": "^2.0.1",
55
- "it-to-stream": "^1.0.0",
56
- "protons-runtime": "^5.0.0",
57
- "stream-to-it": "^0.2.4",
58
- "uint8arraylist": "^2.4.7",
60
+ "protons-runtime": "^5.4.0",
61
+ "uint8arraylist": "^2.4.8",
59
62
  "uint8arrays": "^5.0.1"
60
63
  },
61
64
  "devDependencies": {
62
- "@libp2p/interface-compliance-tests": "^5.2.0",
63
- "@libp2p/logger": "^4.0.5",
64
- "@libp2p/peer-id-factory": "^4.0.5",
65
- "@multiformats/multiaddr": "^12.1.10",
66
- "aegir": "^42.0.0",
67
- "protons": "^7.3.0",
65
+ "@libp2p/interface-compliance-tests": "5.3.0-0c7bbbb07",
66
+ "@libp2p/logger": "4.0.6-0c7bbbb07",
67
+ "@libp2p/peer-id-factory": "4.0.6-0c7bbbb07",
68
+ "@multiformats/multiaddr": "^12.1.14",
69
+ "aegir": "^42.2.3",
70
+ "protons": "^7.5.0",
68
71
  "sinon": "^17.0.1"
69
72
  },
70
73
  "sideEffects": false
package/src/index.ts CHANGED
@@ -18,18 +18,10 @@
18
18
  * ```
19
19
  */
20
20
 
21
- import { TLSSocket, type TLSSocketOptions, connect } from 'node:tls'
22
- import { UnexpectedPeerError } from '@libp2p/interface'
23
- // @ts-expect-error no types
24
- import itToStream from 'it-to-stream'
25
- // @ts-expect-error no types
26
- import streamToIt from 'stream-to-it'
27
- import { generateCertificate, verifyPeerCertificate } from './utils.js'
28
- import type { ComponentLogger, MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId } from '@libp2p/interface'
29
- import type { Duplex } from 'it-stream-types'
30
- import type { Uint8ArrayList } from 'uint8arraylist'
21
+ import { TLS } from './tls.js'
22
+ import type { ComponentLogger, ConnectionEncrypter } from '@libp2p/interface'
31
23
 
32
- const PROTOCOL = '/tls/1.0.0'
24
+ export const PROTOCOL = '/tls/1.0.0'
33
25
 
34
26
  export interface TLSComponents {
35
27
  logger: ComponentLogger
@@ -43,83 +35,6 @@ export interface TLSInit {
43
35
  timeout?: number
44
36
  }
45
37
 
46
- class TLS implements ConnectionEncrypter {
47
- public protocol: string = PROTOCOL
48
- // private readonly log: Logger
49
- // private readonly timeout: number
50
-
51
- // constructor (components: TLSComponents, init: TLSInit = {}) {
52
- // this.log = components.logger.forComponent('libp2p:tls')
53
- // this.timeout = init.timeout ?? 1000
54
- // }
55
-
56
- async secureInbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localId: PeerId, conn: Stream, remoteId?: PeerId): Promise<SecuredConnection<Stream>> {
57
- return this._encrypt(localId, conn, false, remoteId)
58
- }
59
-
60
- async secureOutbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localId: PeerId, conn: Stream, remoteId?: PeerId): Promise<SecuredConnection<Stream>> {
61
- return this._encrypt(localId, conn, true, remoteId)
62
- }
63
-
64
- /**
65
- * Encrypt connection
66
- */
67
- async _encrypt <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localId: PeerId, conn: Stream, isServer: boolean, remoteId?: PeerId): Promise<SecuredConnection<Stream>> {
68
- const opts: TLSSocketOptions = {
69
- ...await generateCertificate(localId),
70
- isServer,
71
- requestCert: true,
72
- // accept self-signed certificates from clients
73
- rejectUnauthorized: false,
74
- // require TLS 1.3 or later
75
- minVersion: 'TLSv1.3'
76
- }
77
-
78
- let socket: TLSSocket
79
-
80
- if (isServer) {
81
- socket = new TLSSocket(itToStream.duplex(conn), opts)
82
- } else {
83
- socket = connect({
84
- socket: itToStream.duplex(conn),
85
- ...opts
86
- })
87
- }
88
-
89
- return new Promise((resolve, reject) => {
90
- function verifyRemote (): void {
91
- const remote = socket.getPeerCertificate()
92
-
93
- verifyPeerCertificate(remote.raw)
94
- .then(remotePeer => {
95
- if (remoteId?.equals(remotePeer) === false) {
96
- throw new UnexpectedPeerError()
97
- }
98
-
99
- const outputStream = streamToIt.duplex(socket)
100
- conn.source = outputStream.source
101
- conn.sink = outputStream.sink
102
-
103
- resolve({
104
- remotePeer,
105
- conn
106
- })
107
- })
108
- .catch(err => {
109
- reject(err)
110
- })
111
- }
112
-
113
- socket.on('error', err => {
114
- reject(err)
115
- })
116
- socket.on('secure', (evt) => {
117
- verifyRemote()
118
- })
119
- })
120
- }
121
- }
122
-
123
38
  export function tls (init?: TLSInit): (components: TLSComponents) => ConnectionEncrypter {
124
- return (components) => new TLS()
39
+ return (components) => new TLS(components, init)
125
40
  }
package/src/tls.ts ADDED
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Implements the spec at https://github.com/libp2p/specs/blob/master/tls/tls.md
5
+ *
6
+ * @example
7
+ *
8
+ * ```typescript
9
+ * import { createLibp2p } from 'libp2p'
10
+ * import { tls } from '@libp2p/tls'
11
+ *
12
+ * const node = await createLibp2p({
13
+ * // ...other options
14
+ * connectionEncryption: [
15
+ * tls()
16
+ * ]
17
+ * })
18
+ * ```
19
+ */
20
+
21
+ import { TLSSocket, type TLSSocketOptions, connect } from 'node:tls'
22
+ import { CodeError } from '@libp2p/interface'
23
+ import { generateCertificate, verifyPeerCertificate, itToStream, streamToIt } from './utils.js'
24
+ import { PROTOCOL } from './index.js'
25
+ import type { TLSComponents, TLSInit } from './index.js'
26
+ import type { MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId, Logger } from '@libp2p/interface'
27
+ import type { Duplex } from 'it-stream-types'
28
+ import type { Uint8ArrayList } from 'uint8arraylist'
29
+
30
+ export class TLS implements ConnectionEncrypter {
31
+ public protocol: string = PROTOCOL
32
+ private readonly log: Logger
33
+ private readonly timeout: number
34
+
35
+ constructor (components: TLSComponents, init: TLSInit = {}) {
36
+ this.log = components.logger.forComponent('libp2p:tls')
37
+ this.timeout = init.timeout ?? 1000
38
+ }
39
+
40
+ async secureInbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localId: PeerId, conn: Stream, remoteId?: PeerId): Promise<SecuredConnection<Stream>> {
41
+ return this._encrypt(localId, conn, false, remoteId)
42
+ }
43
+
44
+ async secureOutbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localId: PeerId, conn: Stream, remoteId?: PeerId): Promise<SecuredConnection<Stream>> {
45
+ return this._encrypt(localId, conn, true, remoteId)
46
+ }
47
+
48
+ /**
49
+ * Encrypt connection
50
+ */
51
+ async _encrypt <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localId: PeerId, conn: Stream, isServer: boolean, remoteId?: PeerId): Promise<SecuredConnection<Stream>> {
52
+ const opts: TLSSocketOptions = {
53
+ ...await generateCertificate(localId),
54
+ isServer,
55
+ // require TLS 1.3 or later
56
+ minVersion: 'TLSv1.3',
57
+ maxVersion: 'TLSv1.3',
58
+ // accept self-signed certificates
59
+ rejectUnauthorized: false
60
+ }
61
+
62
+ let socket: TLSSocket
63
+
64
+ if (isServer) {
65
+ socket = new TLSSocket(itToStream(conn), {
66
+ ...opts,
67
+ // require clients to send certificates
68
+ requestCert: true
69
+ })
70
+ } else {
71
+ socket = connect({
72
+ socket: itToStream(conn),
73
+ ...opts
74
+ })
75
+ }
76
+
77
+ return new Promise((resolve, reject) => {
78
+ const abortTimeout = setTimeout(() => {
79
+ socket.destroy(new CodeError('Handshake timeout', 'ERR_HANDSHAKE_TIMEOUT'))
80
+ }, this.timeout)
81
+
82
+ const verifyRemote = (): void => {
83
+ const remote = socket.getPeerCertificate()
84
+
85
+ verifyPeerCertificate(remote.raw, remoteId, this.log)
86
+ .then(remotePeer => {
87
+ this.log('remote certificate ok, remote peer %p', remotePeer)
88
+
89
+ resolve({
90
+ remotePeer,
91
+ conn: {
92
+ ...conn,
93
+ ...streamToIt(socket)
94
+ }
95
+ })
96
+ })
97
+ .catch(err => {
98
+ reject(err)
99
+ })
100
+ .finally(() => {
101
+ clearTimeout(abortTimeout)
102
+ })
103
+ }
104
+
105
+ socket.on('error', err => {
106
+ reject(err)
107
+ clearTimeout(abortTimeout)
108
+ })
109
+ socket.on('secure', (evt) => {
110
+ this.log('verifying remote certificate')
111
+ verifyRemote()
112
+ })
113
+ })
114
+ }
115
+ }
package/src/utils.ts CHANGED
@@ -1,16 +1,20 @@
1
+ import { Duplex as DuplexStream } from 'node:stream'
1
2
  import { Ed25519PublicKey, Secp256k1PublicKey, marshalPublicKey, supportedKeys, unmarshalPrivateKey, unmarshalPublicKey } from '@libp2p/crypto/keys'
2
- import { CodeError, InvalidCryptoExchangeError } from '@libp2p/interface'
3
+ import { CodeError, InvalidCryptoExchangeError, UnexpectedPeerError } from '@libp2p/interface'
3
4
  import { peerIdFromKeys } from '@libp2p/peer-id'
4
5
  import { AsnConvert } from '@peculiar/asn1-schema'
5
6
  import * as asn1X509 from '@peculiar/asn1-x509'
6
7
  import { Crypto } from '@peculiar/webcrypto'
7
8
  import * as x509 from '@peculiar/x509'
8
9
  import * as asn1js from 'asn1js'
10
+ import { pushable } from 'it-pushable'
9
11
  import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
10
12
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
11
13
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
12
14
  import { KeyType, PublicKey } from '../src/pb/index.js'
13
- import type { PeerId, PublicKey as Libp2pPublicKey } from '@libp2p/interface'
15
+ import type { PeerId, PublicKey as Libp2pPublicKey, Logger } from '@libp2p/interface'
16
+ import type { Duplex } from 'it-stream-types'
17
+ import type { Uint8ArrayList } from 'uint8arraylist'
14
18
 
15
19
  const crypto = new Crypto()
16
20
  x509.cryptoProvider.set(crypto)
@@ -22,23 +26,38 @@ const CERT_VALIDITY_PERIOD_FROM = 60 * 60 * 1000 // ~1 hour
22
26
  // https://github.com/libp2p/go-libp2p/blob/28c0f6ab32cd69e4b18e9e4b550ef6ce059a9d1a/p2p/security/tls/crypto.go#L24C28-L24C44
23
27
  const CERT_VALIDITY_PERIOD_TO = 100 * 365 * 24 * 60 * 60 * 1000 // ~100 years
24
28
 
25
- export async function verifyPeerCertificate (rawCertificate: Uint8Array): Promise<PeerId> {
29
+ export async function verifyPeerCertificate (rawCertificate: Uint8Array, expectedPeerId?: PeerId, log?: Logger): Promise<PeerId> {
26
30
  const now = Date.now()
27
31
  const x509Cert = new x509.X509Certificate(rawCertificate)
28
32
 
29
33
  if (x509Cert.notBefore.getTime() > now) {
34
+ log?.error('the certificate was not valid yet')
30
35
  throw new CodeError('The certificate is not valid yet', 'ERR_INVALID_CERTIFICATE')
31
36
  }
32
37
 
33
38
  if (x509Cert.notAfter.getTime() < now) {
39
+ log?.error('the certificate has expired')
34
40
  throw new CodeError('The certificate has expired', 'ERR_INVALID_CERTIFICATE')
35
41
  }
36
42
 
37
- // TODO: assert chain is only one certificate long
43
+ const certSignatureValid = await x509Cert.verify()
44
+
45
+ if (!certSignatureValid) {
46
+ log?.error('certificate self signature was invalid')
47
+ throw new InvalidCryptoExchangeError('Invalid certificate self signature')
48
+ }
49
+
50
+ const certIsSelfSigned = await x509Cert.isSelfSigned()
51
+
52
+ if (!certIsSelfSigned) {
53
+ log?.error('certificate must be self signed')
54
+ throw new InvalidCryptoExchangeError('Certificate must be self signed')
55
+ }
38
56
 
39
57
  const libp2pPublicKeyExtension = x509Cert.extensions[0]
40
58
 
41
59
  if (libp2pPublicKeyExtension == null || libp2pPublicKeyExtension.type !== LIBP2P_PUBLIC_KEY_EXTENSION) {
60
+ log?.error('the certificate did not include the libp2p public key extension')
42
61
  throw new CodeError('The certificate did not include the libp2p public key extension', 'ERR_INVALID_CERTIFICATE')
43
62
  }
44
63
 
@@ -47,32 +66,40 @@ export async function verifyPeerCertificate (rawCertificate: Uint8Array): Promis
47
66
  // @ts-expect-error deep chain
48
67
  const remotePeerIdPb = libp2pKeySequence.valueBlock.value[0].valueBlock.valueHex
49
68
  const marshalledPeerId = new Uint8Array(remotePeerIdPb, 0, remotePeerIdPb.byteLength)
50
- const remotePeerId = PublicKey.decode(marshalledPeerId)
51
- const remotePeerIdData = remotePeerId.data ?? new Uint8Array(0)
52
- let remotePublicKey: Libp2pPublicKey
53
-
54
- if (remotePeerId.type === KeyType.Ed25519) {
55
- remotePublicKey = new Ed25519PublicKey(remotePeerIdData)
56
- } else if (remotePeerId.type === KeyType.Secp256k1) {
57
- remotePublicKey = new Secp256k1PublicKey(remotePeerIdData)
58
- } else if (remotePeerId.type === KeyType.RSA) {
59
- remotePublicKey = supportedKeys.rsa.unmarshalRsaPublicKey(remotePeerIdData)
69
+ const remotePublicKey = PublicKey.decode(marshalledPeerId)
70
+ const remotePublicKeyData = remotePublicKey.data ?? new Uint8Array(0)
71
+ let remoteLibp2pPublicKey: Libp2pPublicKey
72
+
73
+ if (remotePublicKey.type === KeyType.Ed25519) {
74
+ remoteLibp2pPublicKey = new Ed25519PublicKey(remotePublicKeyData)
75
+ } else if (remotePublicKey.type === KeyType.Secp256k1) {
76
+ remoteLibp2pPublicKey = new Secp256k1PublicKey(remotePublicKeyData)
77
+ } else if (remotePublicKey.type === KeyType.RSA) {
78
+ remoteLibp2pPublicKey = supportedKeys.rsa.unmarshalRsaPublicKey(remotePublicKeyData)
60
79
  } else {
61
- throw new Error('Unknown or unsupported key type')
80
+ log?.error('unknown or unsupported key type', remotePublicKey.type)
81
+ throw new InvalidCryptoExchangeError('Unknown or unsupported key type')
62
82
  }
63
83
 
64
84
  // @ts-expect-error deep chain
65
85
  const remoteSignature = libp2pKeySequence.valueBlock.value[1].valueBlock.valueHex
66
86
  const dataToVerify = encodeSignatureData(x509Cert.publicKey.rawData)
67
- const result = await remotePublicKey.verify(dataToVerify, new Uint8Array(remoteSignature, 0, remoteSignature.byteLength))
87
+ const result = await remoteLibp2pPublicKey.verify(dataToVerify, new Uint8Array(remoteSignature, 0, remoteSignature.byteLength))
68
88
 
69
89
  if (!result) {
70
- throw new Error('Could not verify signature')
90
+ log?.error('invalid libp2p signature')
91
+ throw new InvalidCryptoExchangeError('Could not verify signature')
71
92
  }
72
93
 
73
- const marshalled = marshalPublicKey(remotePublicKey)
94
+ const marshalled = marshalPublicKey(remoteLibp2pPublicKey)
95
+ const remotePeerId = await peerIdFromKeys(marshalled)
74
96
 
75
- return peerIdFromKeys(marshalled)
97
+ if (expectedPeerId?.equals(remotePeerId) === false) {
98
+ log?.error('invalid peer id')
99
+ throw new UnexpectedPeerError()
100
+ }
101
+
102
+ return remotePeerId
76
103
  }
77
104
 
78
105
  export async function generateCertificate (peerId: PeerId): Promise<{ cert: string, key: string }> {
@@ -184,3 +211,109 @@ function formatAsPem (str: string): string {
184
211
 
185
212
  return finalString
186
213
  }
214
+
215
+ export function itToStream (conn: Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>>): DuplexStream {
216
+ const output = pushable()
217
+ const iterator = conn.source[Symbol.asyncIterator]() as AsyncGenerator<Uint8Array>
218
+
219
+ const stream = new DuplexStream({
220
+ autoDestroy: false,
221
+ allowHalfOpen: true,
222
+ write (chunk, encoding, callback) {
223
+ output.push(chunk)
224
+ callback()
225
+ },
226
+ read () {
227
+ iterator.next()
228
+ .then(result => {
229
+ if (result.done === true) {
230
+ this.push(null)
231
+ } else {
232
+ this.push(result.value)
233
+ }
234
+ }, (err) => {
235
+ this.destroy(err)
236
+ })
237
+ }
238
+ })
239
+
240
+ // @ts-expect-error return type of sink is unknown
241
+ conn.sink(output)
242
+ .catch((err: any) => {
243
+ stream.destroy(err)
244
+ })
245
+
246
+ return stream
247
+ }
248
+
249
+ export function streamToIt (stream: DuplexStream): Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> {
250
+ const output: Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = {
251
+ source: (async function * () {
252
+ const output = pushable<Uint8Array>()
253
+
254
+ stream.addListener('data', (buf) => {
255
+ output.push(buf.subarray())
256
+ })
257
+ // both ends closed
258
+ stream.addListener('close', () => {
259
+ output.end()
260
+ })
261
+ stream.addListener('error', (err) => {
262
+ output.end(err)
263
+ })
264
+ // just writable end closed
265
+ stream.addListener('finish', () => {
266
+ output.end()
267
+ })
268
+
269
+ try {
270
+ yield * output
271
+ } catch (err: any) {
272
+ stream.destroy(err)
273
+ throw err
274
+ }
275
+ })(),
276
+ sink: async (source) => {
277
+ try {
278
+ for await (const buf of source) {
279
+ const sendMore = stream.write(buf.subarray())
280
+
281
+ if (!sendMore) {
282
+ await waitForBackpressure(stream)
283
+ }
284
+ }
285
+
286
+ // close writable end
287
+ stream.end()
288
+ } catch (err: any) {
289
+ stream.destroy(err)
290
+ throw err
291
+ }
292
+ }
293
+ }
294
+
295
+ return output
296
+ }
297
+
298
+ async function waitForBackpressure (stream: DuplexStream): Promise<void> {
299
+ await new Promise<void>((resolve, reject) => {
300
+ const continueListener = (): void => {
301
+ cleanUp()
302
+ resolve()
303
+ }
304
+ const stopListener = (err?: Error): void => {
305
+ cleanUp()
306
+ reject(err ?? new Error('Stream ended'))
307
+ }
308
+
309
+ const cleanUp = (): void => {
310
+ stream.removeListener('drain', continueListener)
311
+ stream.removeListener('end', stopListener)
312
+ stream.removeListener('error', stopListener)
313
+ }
314
+
315
+ stream.addListener('drain', continueListener)
316
+ stream.addListener('end', stopListener)
317
+ stream.addListener('error', stopListener)
318
+ })
319
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "TLSComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_tls.TLSComponents.html",
3
- ".:TLSComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_tls.TLSComponents.html",
4
- "TLSInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_tls.TLSInit.html",
5
- ".:TLSInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_tls.TLSInit.html",
6
- "tls": "https://libp2p.github.io/js-libp2p/functions/_libp2p_tls.tls.html",
7
- ".:tls": "https://libp2p.github.io/js-libp2p/functions/_libp2p_tls.tls.html"
8
- }