const tls = require('tls');
const fs = require('fs');
const crypto = require('crypto');
const { createServer } = require('net');
const { promisify } = require('util');
const writeFile = promisify(fs.writeFile);
console.log('ECDH with TLS Example');
console.log('='.repeat(50));
// Configuration
const PORT = 8443;
const HOST = '127.0.0.1';
const CURVE = 'prime256v1';
const MESSAGE = 'Hello from TLS with ECDH!';
// Generate self-signed certificate and key for testing
async function generateCert() {
console.log('Generating self-signed certificate...');
// Generate ECDSA key pair
const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
namedCurve: CURVE,
publicKeyEncoding: { type: 'spki', format: 'pem' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
});
// Create self-signed certificate
const cert = crypto.createCertificate({
serialNumber: '01',
subject: { CN: 'localhost' },
issuer: { CN: 'localhost' },
notBefore: new Date(),
notAfter: new Date(Date.now() + 24 * 60 * 60 * 1000), // 1 day
key: privateKey,
extensions: [
{ name: 'basicConstraints', cA: true },
{
name: 'subjectAltName',
altNames: [
{ type: 2, value: 'localhost' },
{ type: 7, ip: '127.0.0.1' }
]
}
]
});
return { cert, key: privateKey };
}
async function runTlsServer() {
const { cert, key } = await generateCert();
const options = {
key,
cert,
// Enable ECDH cipher suites
ciphers: [
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-AES256-GCM-SHA384',
'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384'
].join(':'),
// Set the curve to use for ECDH key exchange
ecdhCurve: CURVE,
// Only use TLS 1.2 or higher
minVersion: 'TLSv1.2',
// Disable old and insecure protocols
maxVersion: 'TLSv1.3',
// Require client certificate (for mutual TLS)
requestCert: false,
rejectUnauthorized: false
};
// Create TLS server
const server = tls.createServer(options, (socket) => {
console.log('Server: Client connected');
// Log TLS session info
const tlsSocket = socket;
console.log('Server: Cipher:', tlsSocket.getCipher());
console.log('Server: Protocol:', tlsSocket.getProtocol());
console.log('Server: Ephemeral key:', tlsSocket.getEphemeralKeyInfo());
// Handle incoming data
socket.on('data', (data) => {
console.log(`Server received: ${data}`);
socket.write(`Echo: ${data}`);
});
// Handle errors
socket.on('error', (error) => {
console.error('Server error:', error);
});
// Handle connection end
socket.on('end', () => {
console.log('Server: Client disconnected');
});
});
// Start listening
server.listen(PORT, HOST, () => {
console.log(`Server listening on ${HOST}:${PORT}`);
console.log(`Using ECDH curve: ${CURVE}`);
});
return server;
}
async function runTlsClient() {
// Wait for server to start
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('\nConnecting to server...');
const options = {
host: HOST,
port: PORT,
// Allow self-signed certificates
rejectUnauthorized: false,
// Enable ECDH cipher suites
ciphers: [
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-AES256-GCM-SHA384',
'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384'
].join(':'),
// Set the curve to use for ECDH key exchange
ecdhCurve: CURVE,
// Only use TLS 1.2 or higher
minVersion: 'TLSv1.2',
// Disable old and insecure protocols
maxVersion: 'TLSv1.3'
};
const client = tls.connect(options, () => {
console.log('Client: Connected to server');
console.log('Client: Cipher:', client.getCipher());
console.log('Client: Protocol:', client.getProtocol());
console.log('Client: Ephemeral key:', client.getEphemeralKeyInfo());
// Send a message to the server
console.log(`Client sending: ${MESSAGE}`);
client.write(MESSAGE);
});
// Handle incoming data
client.on('data', (data) => {
console.log(`Client received: ${data}`);
// Close the connection after receiving the response
client.end();
});
// Handle connection end
client.on('end', () => {
console.log('Client: Connection closed');
});
// Handle errors
client.on('error', (error) => {
console.error('Client error:', error);
});
return client;
}
// Run the example
async function runExample() {
try {
// Start the server
const server = await runTlsServer();
// Run the client
const client = await runTlsClient();
// Close everything after a delay
setTimeout(() => {
client.end();
server.close();
console.log('Example completed');
}, 5000);
} catch (error) {
console.error('Error:', error);
}
}
// Run the example
runExample();