Elliptisk kurva TLSv1.3 för Node.js

Så... Det här är kort.

Jag tillbringade mycket tid (jag menar fruktansvärt mycket tid) igår för att försäkra mig själv om att de få korta stegen i node.js-dokumenten för TLS är lika lätta att göra med elliptiska kurvor. Efter att ha läst på en massa saker och kört min nyligen säkra applikation är jag äntligen nöjd med att det är OK att bara använda openssl ecparam och ec parametrarna. Och det är OK för att lägga in dem i ett X509-format i slutet för att få filer för node.js TLS-anslutningar.

Varför är det något som du inte bara skulle göra utan att tänka på det? Tja...

  • Problem 1

Jag övertänker saker som en vana.

  • Problem 2

Jag har spelat detta utvecklingsspel i för många år. Så nu är jag misstänksam mot all dokumentation, alla kodavsnitt och alla som säger att han har en snabb lösning.

Användbara artiklar

Artiklarna är användbara för att förklara många saker. Förutom att många är nu ganska många år gamla. Min! Vad tiden går!

Så du börjar öppna många artiklar som returneras av din favoritsökmotor, bara för att hitta en upprepning av den första ett tjugotal artiklar tillbaka med samma kodavsnitt från node.js-dokumentationen.

Till slut var det bästa att läsa openssl-dokumentationen. Se openssl elliptik

Det finns massor av bra artiklar med vackra bilder som förklarar elliptisk kurvkryptografi. En del av det är vackert. Jag måste skriva en recension någon gång. Senare...

Naturligtvis, om du vill gå djupare in i vad TLS-standarden är, kan du alltid fördjupa dig i IETF-dokumenten IETF på TLSv1.3

Varför detta besvär?

Tja... Låt oss säga att du har arbetsprocesser i backend-datorer. De behöver inte alla vara HTTP/S. De kan bara skicka meddelanden runt med sitt eget format. Till exempel använder jag min egen lilla JSON-meddelanderelästack. Hitta den här:message-relay-services

Så du vill bara ha anslutningar; ingen annan overhead.

Och ja, du vill ha säkra anslutningar mellan datorer som inte ens är vända mot omvärlden. Kanske inom ett specifikt kluster kan du avstå från viss säkerhet. Men dessa meddelanden går mellan löst anslutna (små) servrar ganska nära fronten av operationen. Hellre safe than sorry.

Som ett resultat har mitt implementeringsfall till och med specifika klientnycklar som konfigureras på servrarna. Jag har endpoint-servrar (de som äntligen gör något med en tabell på disk eller liknande). De vet vem deras klient är. Naturligtvis, förutom en administratörsskrivbordsapp, är klienten troligen ett meddelandeutbyte i mitten, som betjänar många klienter själv.

Så... Vilka är dessa kommandon?

Ellipserna än en gång!

Här är tvåstegsnyckelgenereringen med openssl:

$ openssl ecparam -name secp384r1 -genkey -out keys/ec_key.pem

$ openssl req -new -x509 -key keys/ec_key.pem -sha256 -nodes -out keys/ec_crt.crt -days 365

Och ja, jag kopierade dem från dokumenten.

Den första genererar den hemliga nyckeln. Lägg märke till att jag lägger den i en nyckel katalog. Katalogen handlar om att hålla nere röran. Lägg den där du behöver den.

Lägg också märke till att jag valde en speciell kurva, secp384r1 . Detta är för 384 bitar av nyckel. Det finns många andra kurvor. Kontrollera node.js-dokumenten för att ta reda på vad de är.

Nästa kommando genererar den publika nyckeln och lägger den i en X509-fil. Filen är certifikatet . req kommando med X509-formatet guidar dig genom att fylla i obligatoriska fält. Fälten är inte magiska, bara var du är och vem du är och ett sätt att kontakta dig.

Det var allt!

Se bara till att du gör detta för servern och klienten.

Använda nycklarna i node.js

Nu är det här exemplen förändras inte. Nedan finns kod om du inte vill följa länkar som denna node.js tls doc.

Koden är från meddelandeförmedlingstjänster. Lägg märke till att jag använde ett konfigurationsobjekt. Filläsningen sker vid initiering. Det är inte säker kod i sig. Senare kan jag flytta filläsningen till en tidigare punkt i initieringen, så att den kan krascha tidigare.

Du kanske frågar:"Kopierar detta i princip dokumenten?" Ja, det gör det, nästan till punkt och pricka. Läs dokumenten .

Men poängen är:

Denna övning har utförts på nodversion v16.6.2

Server:

let base = process.cwd()
const options = {
    key: fs.readFileSync(`${base}/${this.tls_conf.server_key}`),
    cert: fs.readFileSync(`${base}/${this.tls_conf.server_cert}`),
    requestCert: true,  // using client certificate authentication
    ca: [ fs.readFileSync(`${base}/${this.tls_conf.client_cert}`) ] //client uses a self-signed certificate
};
if ( this.extended_tls_options !== false ) {
    options = Object.assign({},options,this.extended_tls_options)
}
this.connection = tls.createServer(options,((sock) => { this.onClientConnected_func(sock) }));    

Klient:

let base = process.cwd()
const tls_options = {
    // Necessary only if the server requires client certificate authentication.
    key: fs.readFileSync(`${base}/${this.tls_conf.client_key}`),
    cert: fs.readFileSync(`${base}/${this.tls_conf.client_cert}`),
    // Necessary only if the server uses a self-signed certificate.
    ca: [ fs.readFileSync(`${base}/${this.tls_conf.server_cert}`) ],
    // Necessary only if the server's cert isn't for "localhost".
    checkServerIdentity: () => { return null; },
};
if ( this.extended_tls_options !== false ) {
    tls_options = Object.assign({},tls_options,this.extended_tls_options)
}
this.socket = tls.connect(this.port, this.address, tls_options, () => {
    if ( this.socket.authorized ) {
        this._connection_handler()
    } else {
        this.socket.end()
    }
    this.writer = this.socket
});

AVSLUTA

Om detta sparade dig tid, så kanske livet har en mening.