Pregunta

Estoy escribiendo un servidor que está aceptando conexiones TCP entrantes. Supongamos que el servidor ha aceptado una conexión TCP, y ya ha recibido 16 (más o menos) bytes desde el cliente. Conociendo estos 16 bytes cómo puede detectar el servidor si el cliente quiere iniciar un protocolo de enlace SSL?

he hecho un experimento que demostró que en mi sistema Linux conectar a localhost (127.0.0.1 ya sea o AF_UNIX) a través de SSL hace que el cliente envíe el siguiente protocolo de enlace (hexdump), seguido de 16 bytes aparentemente al azar:

8064010301004b0000001000003900003800003500001600001300000a07
00c000003300003200002f03008000000500000401008000001500001200
0009060040000014000011000008000006040080000003020080

¿Cómo debe sondear el servidor de estos primeros bytes, sólo para ser capaz de determinar si el cliente está enviando un protocolo de enlace SSL? La sonda debe devolver cierto para todos los protocolos de enlace SSL válido, y debe devolver false con una alta probabilidad de que un mensaje enviado por el cliente que no es un protocolo de enlace SSL. No está permitido utilizar cualquier biblioteca (como OpenSSL) para la sonda. La sonda debe ser un código simple (como unas pocas docenas de líneas en C o Python).

¿Fue útil?

Solución 2

Podría resolver esto en base a la aplicación del método en ClientHello.parse http://tlslite.cvs.sourceforge.net /viewvc/tlslite/tlslite/tlslite/messages.py?view=markup

Me estoy dando dos soluciones aquí en Python. IsSSlClientHandshakeSimple es una expresión regular simple, que puede producir algunos falsos positivos con bastante facilidad; IsSslClientHandshake es más complicado:. comprueba la consistencia de longitudes, y el rango de algunos otros números

import re

def IsSslClientHandshakeSimple(buf):
  return bool(re.match(r'(?s)\A(?:\x80[\x0f-\xff]\x01[\x00-\x09][\x00-\x1f]'
                       r'[\x00-\x05].\x00.\x00.|'
                       r'\x16[\x2c-\xff]\x01\x00[\x00-\x05].'
                       r'[\x00-\x09][\x00-\x1f])', buf))

def IsSslClientHandshake(buf):
  if len(buf) < 2:  # Missing record header.
    return False
  if len(buf) < 2 + ord(buf[1]):  # Incomplete record body.
    return False
  # TODO(pts): Support two-byte lengths in buf[1].
  if ord(buf[0]) == 0x80:  # SSL v2.
    if ord(buf[1]) < 9:  # Message body too short.
      return False
    if ord(buf[2]) != 0x01:  # Not client_hello.
      return False
    if ord(buf[3]) > 9:  # Client major version too large. (Good: 0x03)
      return False
    if ord(buf[4]) > 31:  # Client minor version too large. (Good: 0x01)
      return False
    cipher_specs_size = ord(buf[5]) << 8 | ord(buf[6])
    session_id_size = ord(buf[7]) << 8 | ord(buf[8])
    random_size = ord(buf[9]) << 8 | ord(buf[10])
    if ord(buf[1]) < 9 + cipher_specs_size + session_id_size + random_size:
      return False
    if cipher_specs_size % 3 != 0:  # Cipher specs not a multiple of 3 bytes.
      return False
  elif ord(buf[0]) == 0x16:  # SSL v1.
    # TODO(pts): Test this.
    if ord(buf[1]) < 39:  # Message body too short.
      return False
    if ord(buf[2]) != 0x01:  # Not client_hello.
      return False
    head_size = ord(buf[3]) << 16 | ord(buf[4]) << 8 | ord(buf[5])
    if ord(buf[1]) < head_size + 4:  # Head doesn't fit in message body.
      return False
    if ord(buf[6]) > 9:  # Client major version too large. (Good: 0x03)
      return False
    if ord(buf[7]) > 31:  # Client minor version too large. (Good: 0x01)
      return False
    # random is at buf[8 : 40]
    session_id_size = ord(buf[40])
    i = 41 + session_id_size
    if ord(buf[1]) < i + 2:  # session_id + cipher_suites_size doesn't fit.
      return False
    cipher_specs_size = ord(buf[i]) << 8 | ord(buf[i + 1])
    if cipher_specs_size % 2 != 0:
      return False
    i += 2 + cipher_specs_size
    if ord(buf[1]) < i + 1: # cipher_specs + c..._methods_size doesn't fit.
      return False
    if ord(buf[1]) < i + 1 + ord(buf[i]): # compression_methods doesn't fit.
      return False
  else:  # Not SSL v1 or SSL v2.
    return False
return True

Otros consejos

El cliente siempre envía el mensaje llamado HelloClient primero. Puede ser en formato SSL 2 o SSL 3,0 formato (el mismo formato que en TLS 1.0, 1.1 y 1.2).

Y también hay posibilidad de que SSL 3.0 / TLS 1.0 / 1.1 / 1.2 HelloClient clientes envían con el formato anterior (SSL 2), sólo con el número de versión más alto en los datos. Por lo tanto, la detección de SSL 2 HelloClient es necesaria para utilizar los nuevos clientes también. (Por ejemplo la implementación de Java SSL lo hace)

Vamos a decir 'b' es el búfer. He intentado hacer un diagrama del formato de mensaje.

SSL 2

+-----------------+------+-------
| 2 byte header   | 0x01 | etc.
+-----------------|------+-------
  • b [0] y 0x80 == 0x80 (significa bit más significativo de b [0] es '1')

  • ((b [0] y 0x7f) << 8 | b [1])> 9 (Se Menas el bajo 7 bits de b [0] junto con b [1] son ??la longitud de los datos de Ti. puede tener menos en su memoria intermedia, por lo que no puede comprobarlos. Pero desde el formato de mensaje sabemos que hay 3 campo de 2 bytes (campos de longitud), y al menos un elemento en el campo lista de cifrado (de tamaño 3). por lo tanto, debe haber ser al menos 9 bytes (longitud de datos> = 9).

  • b [2] debe ser 0x01 (tipo de mensaje "ClientHello")

SSL 3.0 o TLS 1.0, 1.1 y 1.2

+-------+------------------+------------------+--------+------
| 0x16  | 2 bytes version  |  2 bytes length  |  0x01  |  etc.
+-------+------------------+------------------+--------+------
  • b [0] == 0x16 (tipo de mensaje "apretón de manos SSL")

  • b [1] debe ser 0x03 (la más reciente versión actualmente importante, pero quién sabe en el futuro?)

  • b [5] debe ser 0x01 (mensaje de protocolo de enlace "HelloClient")

A modo de referencia, se puede ver http://www.mozilla.org/projects /security/pki/nss/ssl/draft02.html y http://tools.ietf.org/html/rfc4346

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top