node-rtc-connection 2.0.4 → 2.0.6
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.
- package/index.cjs +1 -0
- package/index.mjs +1 -0
- package/package.json +10 -47
- package/{dist/types → types}/stun/stun-client.d.ts +2 -0
- package/dist/index.cjs +0 -32
- package/dist/index.mjs +0 -43
- package/src/crypto/der.ts +0 -205
- package/src/crypto/x509.ts +0 -146
- package/src/datachannel/RTCDataChannel.ts +0 -388
- package/src/dtls/RTCCertificate.ts +0 -396
- package/src/dtls/cipher.ts +0 -198
- package/src/dtls/connection.ts +0 -974
- package/src/dtls/prf.ts +0 -62
- package/src/dtls/protocol.ts +0 -204
- package/src/foundation/ByteBufferQueue.ts +0 -237
- package/src/foundation/RTCError.ts +0 -276
- package/src/ice/RTCIceCandidate.ts +0 -349
- package/src/ice/ice-agent.ts +0 -609
- package/src/ice/stun-message.ts +0 -260
- package/src/index.ts +0 -72
- package/src/peerconnection/RTCPeerConnection.ts +0 -430
- package/src/sctp/association.ts +0 -523
- package/src/sctp/chunks.ts +0 -350
- package/src/sctp/crc32c.ts +0 -57
- package/src/sctp/datachannel-manager.ts +0 -187
- package/src/sctp/dcep.ts +0 -94
- package/src/sdp/RTCSessionDescription.ts +0 -115
- package/src/sdp/sdp-utils.ts +0 -229
- package/src/stun/stun-client.ts +0 -936
- package/src/transport-stack.ts +0 -165
- /package/{dist/types → types}/crypto/der.d.ts +0 -0
- /package/{dist/types → types}/crypto/x509.d.ts +0 -0
- /package/{dist/types → types}/datachannel/RTCDataChannel.d.ts +0 -0
- /package/{dist/types → types}/dtls/RTCCertificate.d.ts +0 -0
- /package/{dist/types → types}/dtls/cipher.d.ts +0 -0
- /package/{dist/types → types}/dtls/connection.d.ts +0 -0
- /package/{dist/types → types}/dtls/prf.d.ts +0 -0
- /package/{dist/types → types}/dtls/protocol.d.ts +0 -0
- /package/{dist/types → types}/foundation/ByteBufferQueue.d.ts +0 -0
- /package/{dist/types → types}/foundation/RTCError.d.ts +0 -0
- /package/{dist/types → types}/ice/RTCIceCandidate.d.ts +0 -0
- /package/{dist/types → types}/ice/ice-agent.d.ts +0 -0
- /package/{dist/types → types}/ice/stun-message.d.ts +0 -0
- /package/{dist/types → types}/index.d.ts +0 -0
- /package/{dist/types → types}/peerconnection/RTCPeerConnection.d.ts +0 -0
- /package/{dist/types → types}/sctp/association.d.ts +0 -0
- /package/{dist/types → types}/sctp/chunks.d.ts +0 -0
- /package/{dist/types → types}/sctp/crc32c.d.ts +0 -0
- /package/{dist/types → types}/sctp/datachannel-manager.d.ts +0 -0
- /package/{dist/types → types}/sctp/dcep.d.ts +0 -0
- /package/{dist/types → types}/sdp/RTCSessionDescription.d.ts +0 -0
- /package/{dist/types → types}/sdp/sdp-utils.d.ts +0 -0
- /package/{dist/types → types}/transport-stack.d.ts +0 -0
package/src/crypto/der.ts
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file der.ts
|
|
3
|
-
* @description Minimal ASN.1 DER encoder/decoder for X.509 certificate generation.
|
|
4
|
-
* @module crypto/der
|
|
5
|
-
*
|
|
6
|
-
* Implements just enough of ITU-T X.690 DER to build and read the structures
|
|
7
|
-
* WebRTC needs: self-signed ECDSA certificates and SubjectPublicKeyInfo.
|
|
8
|
-
*
|
|
9
|
-
* All encoders return Buffers. The TLV length is always encoded in the
|
|
10
|
-
* minimal (definite, shortest-form) representation required by DER.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
'use strict';
|
|
14
|
-
|
|
15
|
-
// ASN.1 universal tag numbers (class 0, primitive/constructed as noted).
|
|
16
|
-
export const TAG = Object.freeze({
|
|
17
|
-
BOOLEAN: 0x01,
|
|
18
|
-
INTEGER: 0x02,
|
|
19
|
-
BIT_STRING: 0x03,
|
|
20
|
-
OCTET_STRING: 0x04,
|
|
21
|
-
NULL: 0x05,
|
|
22
|
-
OID: 0x06,
|
|
23
|
-
UTF8_STRING: 0x0c,
|
|
24
|
-
PRINTABLE_STRING: 0x13,
|
|
25
|
-
IA5_STRING: 0x16,
|
|
26
|
-
UTC_TIME: 0x17,
|
|
27
|
-
GENERALIZED_TIME: 0x18,
|
|
28
|
-
SEQUENCE: 0x30, // constructed
|
|
29
|
-
SET: 0x31, // constructed
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Encode a DER length in definite, shortest form.
|
|
34
|
-
* @param {number} len
|
|
35
|
-
* @returns {Buffer}
|
|
36
|
-
*/
|
|
37
|
-
export function encodeLength(len: number): Buffer {
|
|
38
|
-
if (len < 0x80) {
|
|
39
|
-
return Buffer.from([len]);
|
|
40
|
-
}
|
|
41
|
-
const bytes: number[] = [];
|
|
42
|
-
let n = len;
|
|
43
|
-
while (n > 0) {
|
|
44
|
-
bytes.unshift(n & 0xff);
|
|
45
|
-
n >>>= 8;
|
|
46
|
-
}
|
|
47
|
-
return Buffer.from([0x80 | bytes.length, ...bytes]);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Wrap a body in a TLV with the given tag.
|
|
52
|
-
* @param {number} tag
|
|
53
|
-
* @param {Buffer} body
|
|
54
|
-
* @returns {Buffer}
|
|
55
|
-
*/
|
|
56
|
-
export function tlv(tag: number, body: Buffer): Buffer {
|
|
57
|
-
return Buffer.concat([Buffer.from([tag]), encodeLength(body.length), body]);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Encode an unsigned big-endian integer (from a Buffer) as a DER INTEGER,
|
|
62
|
-
* adding a leading 0x00 when the high bit is set so it stays positive.
|
|
63
|
-
* @param {Buffer} buf - Big-endian magnitude.
|
|
64
|
-
* @returns {Buffer}
|
|
65
|
-
*/
|
|
66
|
-
export function encodeIntegerFromBuffer(buf: Buffer): Buffer {
|
|
67
|
-
let start = 0;
|
|
68
|
-
while (start < buf.length - 1 && buf[start] === 0x00) {
|
|
69
|
-
start++; // strip leading zeros (keep at least one byte)
|
|
70
|
-
}
|
|
71
|
-
let body = buf.slice(start);
|
|
72
|
-
if (body[0]! & 0x80) {
|
|
73
|
-
body = Buffer.concat([Buffer.from([0x00]), body]);
|
|
74
|
-
}
|
|
75
|
-
return tlv(TAG.INTEGER, body);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Encode a small non-negative JS integer as a DER INTEGER.
|
|
80
|
-
* @param {number} value
|
|
81
|
-
* @returns {Buffer}
|
|
82
|
-
*/
|
|
83
|
-
export function encodeInteger(value: number): Buffer {
|
|
84
|
-
if (value === 0) {
|
|
85
|
-
return tlv(TAG.INTEGER, Buffer.from([0x00]));
|
|
86
|
-
}
|
|
87
|
-
const bytes: number[] = [];
|
|
88
|
-
let n = value;
|
|
89
|
-
while (n > 0) {
|
|
90
|
-
bytes.unshift(n & 0xff);
|
|
91
|
-
n = Math.floor(n / 256);
|
|
92
|
-
}
|
|
93
|
-
if (bytes[0]! & 0x80) {
|
|
94
|
-
bytes.unshift(0x00);
|
|
95
|
-
}
|
|
96
|
-
return tlv(TAG.INTEGER, Buffer.from(bytes));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Encode an OBJECT IDENTIFIER from its dotted-decimal string.
|
|
101
|
-
* @param {string} oid - e.g. "1.2.840.10045.2.1"
|
|
102
|
-
* @returns {Buffer}
|
|
103
|
-
*/
|
|
104
|
-
export function encodeOID(oid: string): Buffer {
|
|
105
|
-
const parts = oid.split('.').map(Number);
|
|
106
|
-
if (parts.length < 2) {
|
|
107
|
-
throw new Error(`Invalid OID: ${oid}`);
|
|
108
|
-
}
|
|
109
|
-
const bytes = [40 * parts[0]! + parts[1]!];
|
|
110
|
-
for (let i = 2; i < parts.length; i++) {
|
|
111
|
-
let v = parts[i]!;
|
|
112
|
-
const stack = [v & 0x7f];
|
|
113
|
-
v = Math.floor(v / 128);
|
|
114
|
-
while (v > 0) {
|
|
115
|
-
stack.unshift((v & 0x7f) | 0x80);
|
|
116
|
-
v = Math.floor(v / 128);
|
|
117
|
-
}
|
|
118
|
-
bytes.push(...stack);
|
|
119
|
-
}
|
|
120
|
-
return tlv(TAG.OID, Buffer.from(bytes));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Encode a BIT STRING with zero unused bits.
|
|
125
|
-
* @param {Buffer} data
|
|
126
|
-
* @returns {Buffer}
|
|
127
|
-
*/
|
|
128
|
-
export function encodeBitString(data: Buffer): Buffer {
|
|
129
|
-
return tlv(TAG.BIT_STRING, Buffer.concat([Buffer.from([0x00]), data]));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Encode an OCTET STRING.
|
|
134
|
-
* @param {Buffer} data
|
|
135
|
-
* @returns {Buffer}
|
|
136
|
-
*/
|
|
137
|
-
export function encodeOctetString(data: Buffer): Buffer {
|
|
138
|
-
return tlv(TAG.OCTET_STRING, data);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Encode a SEQUENCE from already-encoded components.
|
|
143
|
-
* @param {Buffer[]} components
|
|
144
|
-
* @returns {Buffer}
|
|
145
|
-
*/
|
|
146
|
-
export function encodeSequence(components: Buffer[]): Buffer {
|
|
147
|
-
return tlv(TAG.SEQUENCE, Buffer.concat(components));
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Encode a SET from already-encoded components.
|
|
152
|
-
* @param {Buffer[]} components
|
|
153
|
-
* @returns {Buffer}
|
|
154
|
-
*/
|
|
155
|
-
export function encodeSet(components: Buffer[]): Buffer {
|
|
156
|
-
return tlv(TAG.SET, Buffer.concat(components));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Encode NULL.
|
|
161
|
-
* @returns {Buffer}
|
|
162
|
-
*/
|
|
163
|
-
export function encodeNull(): Buffer {
|
|
164
|
-
return tlv(TAG.NULL, Buffer.alloc(0));
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Encode a UTF8String.
|
|
169
|
-
* @param {string} str
|
|
170
|
-
* @returns {Buffer}
|
|
171
|
-
*/
|
|
172
|
-
export function encodeUTF8String(str: string): Buffer {
|
|
173
|
-
return tlv(TAG.UTF8_STRING, Buffer.from(str, 'utf8'));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Encode a context-specific [n] explicit wrapper (constructed).
|
|
178
|
-
* @param {number} n - context tag number
|
|
179
|
-
* @param {Buffer} body
|
|
180
|
-
* @returns {Buffer}
|
|
181
|
-
*/
|
|
182
|
-
export function encodeExplicit(n: number, body: Buffer): Buffer {
|
|
183
|
-
return tlv(0xa0 | n, body);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Encode an X.509 time. Uses UTCTime for years < 2050, else GeneralizedTime,
|
|
188
|
-
* per RFC 5280 §4.1.2.5.
|
|
189
|
-
* @param {Date} date
|
|
190
|
-
* @returns {Buffer}
|
|
191
|
-
*/
|
|
192
|
-
export function encodeTime(date: Date): Buffer {
|
|
193
|
-
const yyyy = date.getUTCFullYear();
|
|
194
|
-
const pad = (v: number, n = 2): string => String(v).padStart(n, '0');
|
|
195
|
-
const mm = pad(date.getUTCMonth() + 1);
|
|
196
|
-
const dd = pad(date.getUTCDate());
|
|
197
|
-
const hh = pad(date.getUTCHours());
|
|
198
|
-
const mi = pad(date.getUTCMinutes());
|
|
199
|
-
const ss = pad(date.getUTCSeconds());
|
|
200
|
-
if (yyyy < 2050) {
|
|
201
|
-
const yy = pad(yyyy % 100);
|
|
202
|
-
return tlv(TAG.UTC_TIME, Buffer.from(`${yy}${mm}${dd}${hh}${mi}${ss}Z`, 'ascii'));
|
|
203
|
-
}
|
|
204
|
-
return tlv(TAG.GENERALIZED_TIME, Buffer.from(`${yyyy}${mm}${dd}${hh}${mi}${ss}Z`, 'ascii'));
|
|
205
|
-
}
|
package/src/crypto/x509.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file x509.ts
|
|
3
|
-
* @description Self-signed X.509 v3 certificate generation for WebRTC DTLS.
|
|
4
|
-
* @module crypto/x509
|
|
5
|
-
*
|
|
6
|
-
* WebRTC peers authenticate by self-signed certificate. The SDP carries
|
|
7
|
-
* a=fingerprint as the hash of the DER-encoded certificate (RFC 8122), which
|
|
8
|
-
* the peer verifies against the certificate presented during the DTLS
|
|
9
|
-
* handshake. Node has no certificate builder, so we assemble a minimal but
|
|
10
|
-
* spec-valid ECDSA P-256 / ecdsa-with-SHA256 certificate by hand.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
'use strict';
|
|
14
|
-
|
|
15
|
-
import * as crypto from 'crypto';
|
|
16
|
-
import * as der from './der';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Options for {@link generateSelfSigned}.
|
|
20
|
-
*/
|
|
21
|
-
export interface GenerateSelfSignedOptions {
|
|
22
|
-
/** CN; WebRTC uses a random value. */
|
|
23
|
-
commonName?: string;
|
|
24
|
-
/** Validity period in days. */
|
|
25
|
-
days?: number;
|
|
26
|
-
/** Override start time (default: now - 1 day). */
|
|
27
|
-
notBefore?: Date;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Result of {@link generateSelfSigned}.
|
|
32
|
-
*/
|
|
33
|
-
export interface SelfSignedCertificate {
|
|
34
|
-
/** DER-encoded certificate. */
|
|
35
|
-
certDer: Buffer;
|
|
36
|
-
privateKey: crypto.KeyObject;
|
|
37
|
-
publicKey: crypto.KeyObject;
|
|
38
|
-
notBefore: Date;
|
|
39
|
-
notAfter: Date;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// OIDs used in the certificate.
|
|
43
|
-
export const OID = Object.freeze({
|
|
44
|
-
ecPublicKey: '1.2.840.10045.2.1',
|
|
45
|
-
prime256v1: '1.2.840.10045.3.1.7',
|
|
46
|
-
ecdsaWithSHA256: '1.2.840.10045.4.3.2',
|
|
47
|
-
commonName: '2.5.4.3',
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Build a Name with a single CN RDN.
|
|
52
|
-
* @param {string} cn
|
|
53
|
-
* @returns {Buffer}
|
|
54
|
-
*/
|
|
55
|
-
function buildName(cn: string): Buffer {
|
|
56
|
-
const attr = der.encodeSequence([
|
|
57
|
-
der.encodeOID(OID.commonName),
|
|
58
|
-
der.encodeUTF8String(cn),
|
|
59
|
-
]);
|
|
60
|
-
const rdn = der.encodeSet([attr]);
|
|
61
|
-
return der.encodeSequence([rdn]);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* The AlgorithmIdentifier for ecdsa-with-SHA256 (no parameters).
|
|
66
|
-
* @returns {Buffer}
|
|
67
|
-
*/
|
|
68
|
-
function ecdsaWithSHA256AlgId(): Buffer {
|
|
69
|
-
return der.encodeSequence([der.encodeOID(OID.ecdsaWithSHA256)]);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Generate a self-signed ECDSA P-256 certificate.
|
|
74
|
-
*
|
|
75
|
-
* @param {GenerateSelfSignedOptions} [options]
|
|
76
|
-
* @returns {SelfSignedCertificate}
|
|
77
|
-
*/
|
|
78
|
-
export function generateSelfSigned(
|
|
79
|
-
options: GenerateSelfSignedOptions = {}
|
|
80
|
-
): SelfSignedCertificate {
|
|
81
|
-
const commonName =
|
|
82
|
-
options.commonName || `WebRTC-${crypto.randomBytes(8).toString('hex')}`;
|
|
83
|
-
const days = options.days || 30;
|
|
84
|
-
|
|
85
|
-
const { publicKey, privateKey } = crypto.generateKeyPairSync('ec', {
|
|
86
|
-
namedCurve: 'prime256v1',
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// Node exports a complete SubjectPublicKeyInfo in DER — reuse verbatim.
|
|
90
|
-
const spki = publicKey.export({ type: 'spki', format: 'der' }) as Buffer;
|
|
91
|
-
|
|
92
|
-
// Validity. Start one day in the past to tolerate clock skew between peers.
|
|
93
|
-
const notBefore =
|
|
94
|
-
options.notBefore || new Date(Date.now() - 24 * 60 * 60 * 1000);
|
|
95
|
-
const notAfter = new Date(notBefore.getTime() + days * 24 * 60 * 60 * 1000);
|
|
96
|
-
|
|
97
|
-
// Serial number: positive 20-byte random (high bit cleared via encoder).
|
|
98
|
-
const serial = crypto.randomBytes(20);
|
|
99
|
-
serial[0]! &= 0x7f;
|
|
100
|
-
if (serial[0] === 0) serial[0] = 0x01;
|
|
101
|
-
|
|
102
|
-
const name = buildName(commonName);
|
|
103
|
-
|
|
104
|
-
// TBSCertificate (X.509 v3).
|
|
105
|
-
const tbs = der.encodeSequence([
|
|
106
|
-
der.encodeExplicit(0, der.encodeInteger(2)), // version v3 (value 2)
|
|
107
|
-
der.encodeIntegerFromBuffer(serial), // serialNumber
|
|
108
|
-
ecdsaWithSHA256AlgId(), // signature algorithm
|
|
109
|
-
name, // issuer (== subject, self-signed)
|
|
110
|
-
der.encodeSequence([der.encodeTime(notBefore), der.encodeTime(notAfter)]),
|
|
111
|
-
name, // subject
|
|
112
|
-
spki, // subjectPublicKeyInfo
|
|
113
|
-
]);
|
|
114
|
-
|
|
115
|
-
// Sign the TBS. Node returns a DER ECDSA-Sig-Value (SEQUENCE { r, s }).
|
|
116
|
-
const signature = crypto.sign('sha256', tbs, privateKey);
|
|
117
|
-
|
|
118
|
-
const certDer = der.encodeSequence([
|
|
119
|
-
tbs,
|
|
120
|
-
ecdsaWithSHA256AlgId(),
|
|
121
|
-
der.encodeBitString(signature),
|
|
122
|
-
]);
|
|
123
|
-
|
|
124
|
-
return { certDer, privateKey, publicKey, notBefore, notAfter };
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Compute the certificate fingerprint as used in SDP a=fingerprint (RFC 8122):
|
|
129
|
-
* hash over the DER-encoded certificate, uppercase hex, colon-separated.
|
|
130
|
-
*
|
|
131
|
-
* @param {Buffer} certDer
|
|
132
|
-
* @param {string} [algorithm='sha-256'] - 'sha-256' | 'sha-384' | 'sha-512'
|
|
133
|
-
* @returns {string}
|
|
134
|
-
*/
|
|
135
|
-
export function fingerprint(
|
|
136
|
-
certDer: Buffer,
|
|
137
|
-
algorithm: string = 'sha-256'
|
|
138
|
-
): string {
|
|
139
|
-
const nodeAlgo = algorithm.replace('-', '').toLowerCase(); // sha-256 -> sha256
|
|
140
|
-
const digest = crypto
|
|
141
|
-
.createHash(nodeAlgo)
|
|
142
|
-
.update(certDer)
|
|
143
|
-
.digest('hex')
|
|
144
|
-
.toUpperCase();
|
|
145
|
-
return digest.match(/.{2}/g)!.join(':');
|
|
146
|
-
}
|