TLS Nativo

Compatible con

 

TsgcWebSocketClient

TsgcTCPClient

TsgcHTTP1Client

TsgcHTTP2Client

TsgcWebSocketServer

TsgcWebSocketHTTPServer

TsgcHTTPServer

TsgcWebSocketProxyServer

TsgcWebSocketLoadBalancerServer

 

*Requiere el paquete sgcCrypto, que se incluye a partir de la edición Standard.

 

El motor TLS nativo es una implementación de TLS 1.3 y TLS 1.2 escrita íntegramente en Object Pascal sobre las unidades sgcCrypto. No es un enlace a otra biblioteca: no hay ninguna DLL de OpenSSL que desplegar, ninguna llamada a SChannel ni ninguna biblioteca TLS de la plataforma de por medio. El mismo código fuente compila desde Delphi 7 hasta RAD Studio 13 y funciona en todas las plataformas que admiten los componentes.

 

La razón para recurrir a él es el intercambio de claves. El motor ofrece los grupos híbridos poscuánticos de RFC 10024, y X25519MLKEM768 es el primer grupo que propone, de modo que un cliente que cambie a él negocia un intercambio de claves poscuántico contra cualquier servidor que admita uno, sin ningún otro cambio en la aplicación. Los grupos híbridos solo existen en TLS 1.3, así que una conexión que recurre a TLS 1.2 usa una curva clásica. Consulte Criptografía Poscuántica para saber qué son esos grupos y por qué un híbrido es hoy la migración razonable.

 

Cómo activarlo

 

Establezca el IOHandler y no cambia nada más. Las propiedades de certificado, clave, certificado raíz, verificación y ALPN que ya utiliza siguen funcionando, el motor lee esas mismas.

 


// client
oClient := TsgcWebSocketClient.Create(nil);
oClient.URL := 'wss://www.esegece.com:2053';
oClient.TLS := True;
oClient.TLSOptions.IOHandler := iohNativeTLS;
oClient.TLSOptions.VerifyCertificate := True;
oClient.TLSOptions.RootCertFile := 'cacert.pem';
oClient.Active := True;

// server
oServer := TsgcWebSocketServer.Create(nil);
oServer.SSL := True;
oServer.SSLOptions.IOHandler := iohNativeTLS;
oServer.SSLOptions.CertFile := 'certificate.pem';
oServer.SSLOptions.KeyFile := 'key.pem';
oServer.Active := True;

 

En un servidor, el motor funciona también sobre los motores dirigidos por eventos. Establezca IOHandlerOptions.IOHandlerType en iohIOCP en Windows o en iohEPOLL en Linux y el manejador se construye sobre el Proveedor TLS correspondiente, de modo que la misma configuración funciona en los tres motores.

 

Seleccionar iohNativeTLS en una compilación sin el paquete sgcCrypto genera una excepción que así lo indica, en lugar de recurrir en silencio a otra biblioteca.

 

Versiones de TLS

 

El motor habla TLS 1.3 y TLS 1.2, como cliente y como servidor, en el cliente Indy, en el servidor Indy y en los motores de servidor IOCP y EPOLL. TLS 1.3 se elige siempre que ambos extremos lo admiten. En el motor nativo, TLSOptions.Version en un cliente y SSLOptions.Version en un servidor es la versión mínima permitida.

 

Versión Negocia
tlsUndefined (el valor predeterminado) TLS 1.3 o TLS 1.2
tls1_2 TLS 1.3 o TLS 1.2
tls1_3 Solo TLS 1.3
tls1_0, tls1_1 Nada. Un cliente genera un error de configuración al conectarse, y un servidor al arrancar, porque el motor solo admite TLS 1.2 y TLS 1.3.

 

Esto es distinto de cómo lee la propiedad el manejador de OpenSSL. Con iohOpenSSL, tls1_2 significa exactamente TLS 1.2, mientras que con iohNativeTLS significa TLS 1.2 o posterior. La lista de suites de cifrado decide el resto. Para obtener solo TLS 1.2, mantenga Version en tls1_2 e indique únicamente suites de TLS 1.2 en NativeTLS_Options.CipherSuites. Una lista que indique solo suites de TLS 1.3 da solo TLS 1.3, y una lista que indique suites de ambas versiones permite las dos. Version en tls1_3 junto con una lista de suites de TLS 1.2 no deja ninguna versión que negociar, y la conexión genera un error al iniciarse.

 


// TLS 1.3 and TLS 1.2, tls1_2 is the lowest version allowed
oClient.TLSOptions.IOHandler := iohNativeTLS;
oClient.TLSOptions.Version := tls1_2;

// TLS 1.3 only
oClient.TLSOptions.Version := tls1_3;

// TLS 1.2 only: name TLS 1.2 suites and no TLS 1.3 suite
oClient.TLSOptions.Version := tls1_2;
oClient.TLSOptions.NativeTLS_Options.CipherSuites :=
  'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256';

 

Grupos y suites de cifrado

 

TLSOptions.NativeTLS_Options en un cliente, y SSLOptions.NativeTLS_Options en un servidor, contienen las dos listas de preferencia. Ambas son cadenas al estilo de OpenSSL, con los elementos separados por dos puntos y el preferido en primer lugar, y una única lista sirve tanto para TLS 1.3 como para TLS 1.2. Deje una vacía para conservar el valor predeterminado del motor. Una lista inválida genera un error al iniciarse la conexión, así que un error de escritura no se ignora en silencio.

 

Propiedad Nombres aceptados Predeterminado
Groups X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024, X25519, secp256r1, secp384r1. También se aceptan los alias P-256, prime256v1 y P-384, y los nombres se comparan sin distinguir mayúsculas de minúsculas. Los tres grupos híbridos son exclusivos de TLS 1.3. X25519MLKEM768:X25519:secp256r1:secp384r1
CipherSuites TLS 1.3: TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256. TLS 1.2: las suites de la tabla siguiente. Se aceptan tanto los nombres IANA como los nombres al estilo de OpenSSL, como ECDHE-RSA-AES128-GCM-SHA256, y el motor informa el nombre IANA. TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256, más los valores predeterminados de TLS 1.2 indicados abajo

 

El primer grupo de la lista es aquel para el que un cliente envía un key share, así que dejar X25519MLKEM768 al principio es lo que hace que el primer envío ya sea poscuántico. Anteponer un signo de interrogación a un elemento hace que se omita cuando esta compilación no lo incluye, y cualquier otro elemento desconocido o no disponible hace fallar la lista entera.

 


// only the hybrid post-quantum groups, and only AES-256-GCM
oClient.TLSOptions.NativeTLS_Options.Groups :=
  'X25519MLKEM768:SecP256r1MLKEM768:SecP384r1MLKEM1024';
oClient.TLSOptions.NativeTLS_Options.CipherSuites := 'TLS_AES_256_GCM_SHA384';

// tolerate a build where X25519 is not compiled in
oClient.TLSOptions.NativeTLS_Options.Groups := '?X25519MLKEM768:secp256r1';

 

Suites de cifrado de TLS 1.2

 

De forma predeterminada solo están habilitadas las suites AEAD con secreto hacia adelante. Las suites AES-CBC y el intercambio de claves RSA existen para los pares que no puedan hacerlo mejor, y solo se ofrecen o se aceptan cuando CipherSuites las nombra.

 

Suites Habilitadas
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 De forma predeterminada, en este orden.
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 Solo cuando se nombran en CipherSuites.
TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA256 Solo cuando se nombran en CipherSuites. El intercambio de claves RSA no tiene secreto hacia adelante.

 

Las suites ECDHE de una conexión TLS 1.2 usan un grupo clásico de la lista Groups, X25519, secp256r1 o secp384r1, así que mantenga al menos uno de ellos en la lista cuando deban conectarse pares con TLS 1.2. El intercambio de claves RSA no usa ningún grupo.

 


// TLS 1.3, and TLS 1.2 with AES-GCM plus AES-CBC for older clients
oServer.SSLOptions.IOHandler := iohNativeTLS;
oServer.SSLOptions.Version := tls1_2;
oServer.SSLOptions.NativeTLS_Options.CipherSuites :=
  'TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:' +
  'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:' +
  'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA';

 

En una compilación hecha con SGC_CRYPTO_FIPS los dos grupos construidos sobre X25519, las suites ChaCha20-Poly1305 y el intercambio de claves RSA quedan fuera de la compilación, y los valores predeterminados pasan a ser SecP256r1MLKEM768:SecP384r1MLKEM1024:secp256r1:secp384r1 y TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256, con las cuatro suites ECDHE AES-GCM para TLS 1.2. Consulte Modo FIPS.

 

Comportamiento de TLS 1.2

 

TLS 1.2 está implementado con las protecciones que espera un par moderno, y sin las partes del protocolo que causaron sus ataques conocidos.

 

Reanudación de sesión

 

El motor reanuda sesiones con tickets de sesión sin estado, en TLS 1.3 (RFC 8446) y en TLS 1.2 (RFC 5077). Tras un protocolo de enlace completo el servidor envía un ticket, sellado con AES-256-GCM bajo una clave que solo posee el servidor. El cliente lo guarda en una caché de sesión, indexada por host, puerto y lista ALPN, y lo ofrece en la siguiente conexión, que entonces omite el intercambio de certificados. Un ticket que el servidor no puede abrir, o uno que ha caducado, da lugar a un protocolo de enlace completo con un ticket nuevo.

 

Propiedad Predeterminado Significado
NativeTLS_Options.SessionTickets True Un servidor emite tickets y un cliente los guarda y los ofrece. False desactiva la reanudación, y entonces cada protocolo de enlace es completo.
NativeTLS_Options.TicketLifetime 7200 Solo servidor. Segundos durante los que un ticket puede usarse para reanudar, como máximo 604800. La clave de ticket del servidor rota cada TicketLifetime segundos, y la clave anterior sigue siendo válida durante un periodo más.

 

Las opciones son TLSOptions.NativeTLS_Options en un cliente y SSLOptions.NativeTLS_Options en un servidor. La caché de sesión pertenece a cada componente cliente, de modo que las reconexiones del mismo TsgcWebSocketClient, TsgcHTTP1Client, TsgcTCPClient o TsgcLDAPClient se reanudan, y también lo hace la conexión ascendente de TsgcWebSocketProxyServer.

 

La reanudación en TLS 1.2 requiere el extended master secret de la RFC 7627. Una sesión TLS 1.2 sin él nunca se reanuda y no recibe ningún ticket, y tampoco se emite ningún ticket cuando el servidor pide un certificado de cliente. Un ticket de TLS 1.3 nunca se abre como sesión TLS 1.2, ni al revés.

 

Si una conexión se reanudó lo informa la propiedad Resumed de TsgcIdSSLIOHandlerSocketNativeTLS, el manejador descrito más abajo.

 

Lo que se negoció

 

Una vez completado el protocolo de enlace, el manejador del cliente, TsgcIdSSLIOHandlerSocketNativeTLS en la unidad sgcSSL_NativeTLS_Indy, informa del resultado. VersionName es TLSv1.2 o TLSv1.3, CipherSuiteName es el nombre IANA de la suite, GroupName es el grupo del intercambio de claves, vacío en el intercambio de claves RSA, y PeerSignatureSchemeName es el esquema de firma que usó el servidor. El manejador es el que el cliente pasa a OnSSLAfterCreateHandler.

 


procedure TForm1.oClientSSLAfterCreateHandler(Sender: TObject;
  aType: TwsSSLHandler; aSSLHandler: TIdSSLIOHandlerSocketBase);
begin
  FHandler := aSSLHandler;
end;

procedure TForm1.oClientConnect(Connection: TsgcWSConnection);
var
  oHandler: TsgcIdSSLIOHandlerSocketNativeTLS;
begin
  if FHandler is TsgcIdSSLIOHandlerSocketNativeTLS then
  begin
    oHandler := TsgcIdSSLIOHandlerSocketNativeTLS(FHandler);
    Memo1.Lines.Add(oHandler.VersionName + ' ' + oHandler.CipherSuiteName +
      ' ' + oHandler.GroupName + ' ' + oHandler.PeerSignatureSchemeName);
  end;
end;

 

Certificados y verificación

 

Un servidor lee CertFile, KeyFile y Password. CertFile y KeyFile pueden ser PEM, o CertFile puede ser un archivo .pfx o .p12, reconocido por su extensión. Un archivo PKCS#12 contiene el certificado, la cadena y la clave privada, así que KeyFile no es necesario, y se abre con Password. Lo lee el lector PKCS#12 en Pascal puro de sgcCrypto_PKCS12, sin OpenSSL. Un cliente que establece VerifyCertificate en True comprueba la cadena del servidor frente a las raíces de confianza descritas más abajo y comprueba que el nombre coincide con el host al que se ha conectado. VerifyDepth se transmite tal cual, y un valor superior a 16 se limita a 16.

 

Las raíces de confianza son los certificados de RootCertFile. Establecer NativeTLS_Options.UseSystemRoots en True añade las autoridades de certificación en las que confía el sistema operativo. Es False de forma predeterminada. Las dos se combinan: primero se cargan las raíces de RootCertFile, las raíces del sistema se añaden al mismo almacén, y una cadena se acepta cuando lleva a cualquiera de ellas. Cuando no se encuentra ninguna raíz del sistema, no se añade nada y no se genera ningún error, de modo que la verificación depende únicamente de RootCertFile. La propiedad es TLSOptions.NativeTLS_Options.UseSystemRoots en un cliente y SSLOptions.NativeTLS_Options.UseSystemRoots en un servidor, donde las raíces solo sirven para validar certificados de cliente. El origen de las raíces del sistema depende de la plataforma:

Para cargar usted mismo una carpeta de archivos de certificado, TsgcTLS13TrustStore.AddDirectory(aDirectory, aRemovedDirectory) en la unidad sgcSSL_NativeTLS_Certificates lee cada archivo PEM o DER de aDirectory, omite cualquier archivo cuyo nombre también exista en aRemovedDirectory, y devuelve cuántos certificados añadió. Funciona en todas las plataformas.

 

Para fijar el nombre que debe llevar el certificado en lugar de usar el host de la conexión, establezca TLSOptions.OpenSSL_Options.X509Checks.HostName o IPAddress, con el indicador correspondiente en X509Checks.Mode. El motor lee esos dos valores aunque no sea OpenSSL, de modo que la propiedad significa lo mismo sea cual sea el IOHandler seleccionado.

 

En un servidor, SSLOptions.VerifyCertificate pide un certificado al cliente y lo valida frente a las raíces de confianza descritas más arriba, y SSLOptions.VerifyCertificate_Options.FailIfNoCertificate rechaza a un cliente que no envía ninguno. VerifyClientOnce no tiene nada que hacer aquí. TLS 1.3 no tiene renegociación, y el motor la rechaza en TLS 1.2, así que nunca lo pide una segunda vez.

 

ALPN funciona como siempre mediante ALPNProtocols en un cliente y mediante la selección de ALPN del servidor, de modo que HTTP/2 sobre el motor nativo negocia h2 igual que lo hace sobre OpenSSL. Consulte ALPN.

Modo QUIC

 

El motor también ejecuta el protocolo de enlace TLS 1.3 de QUIC y HTTP/3 (RFC 9001). Establezca SSLQUICOptions.IOHandler en TsgcQUICClient, TLSOptions.IOHandler en TsgcHTTP3Client, QUICOptions.SSLOptions.IOHandler en TsgcQUICServer y TsgcHTTP3Server, o SSLOptions.IOHandler en un servidor con HTTP3Options.Enabled, en iohNativeTLS.

 

 

Consulte QUIC para la comparación de motores.

 

Lo que no hace

 

El motor es deliberadamente limitado. Todo lo que sigue es un límite real, no un ajuste que haya que buscar.

 

 

Nada de lo que envíe el par genera una excepción. Un fallo de protocolo termina la conexión con la alerta TLS que corresponde, y el motivo se informa mediante los eventos de error del componente como de costumbre.

La protección de registros AES-GCM y AES-CBC utiliza las instrucciones AES-NI y PCLMULQDQ en compilaciones Windows hechas con Delphi cuando la CPU las tiene, vea sgcAES_HardwareAvailable en Cifrado Simétrico. Para una compilación en la que ninguna parte de la biblioteca carga OpenSSL, vea Ejecutar sin OpenSSL.