Question

J'écris un serveur qui accepte les connexions TCP entrantes. Supposons que le serveur a accepté une connexion TCP, et a déjà reçu 16 (environ) octets du client. Sachant ces 16 octets comment le serveur détecter si le client veut lancer une poignée de main SSL?

Je l'ai fait une expérience qui a montré que sur mon système Linux se connecter à localhost (soit 127.0.0.1 ou AF_UNIX) via SSL rend le client envoie la poignée de main suivante (hexdump), suivi de 16 octets apparemment aléatoire:

8064010301004b0000001000003900003800003500001600001300000a07
00c000003300003200002f03008000000500000401008000001500001200
0009060040000014000011000008000006040080000003020080

Comment sonder le serveur ces premiers octets, juste pour être en mesure de déterminer si le client envoie une poignée de main SSL? La sonde doit retourner vrai pour toutes les authentifications SSL valides, et il doit retourner faux avec une forte probabilité pour un message envoyé par le client qui n'est pas une poignée de main SSL. Il est interdit d'utiliser les bibliothèques (comme OpenSSL) pour la sonde. La sonde doit être un simple code (tel que quelques dizaines de lignes en C ou Python).

Était-ce utile?

La solution 2

Je pourrais comprendre cela sur la base de la mise en œuvre de la méthode ClientHello.parse dans http://tlslite.cvs.sourceforge.net /viewvc/tlslite/tlslite/tlslite/messages.py?view=markup

Je donne deux solutions ici en Python. IsSSlClientHandshakeSimple est une expression régulière simple, qui peut donner des faux positifs assez facilement; IsSslClientHandshake est plus compliquée:. il vérifie la cohérence des longueurs, et l'ordre de quelques autres chiffres

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

Autres conseils

Le client envoie toujours appelé ainsi un message HelloClient premier. Il peut être au format SSL 2 ou au format SSL 3.0 (le même format que dans TLS 1.0, 1.1 et 1.2).

Et il y a aussi la possibilité que SSL 3.0 / TLS 1.0 / 1.1 / 1.2 clients envoient HelloClient avec l'ancien format (SSL 2), juste avec le numéro de version plus élevé dans les données. Ainsi, la détection de SSL 2 HelloClient neccessaire pour les nouveaux clients aussi. (Par exemple la mise en œuvre Java SSL le fait)

'b' de dire Let est votre tampon. J'ai essayé de schématiser le format du message.

SSL 2

+-----------------+------+-------
| 2 byte header   | 0x01 | etc.
+-----------------|------+-------
  • b [0] == 0x80 & 0x80 (cela signifie bit le plus significatif de b [0] est '1')

  • ((b [0] & 0x7F) << 8 | b [1])> 9 (Il Menas le faible 7 bits de b [0] avec b [1] ont une longueur de données que vous. peut avoir moins dans votre mémoire tampon, de sorte que vous ne pouvez pas les vérifier. Mais à partir du format de message que nous savons qu'il ya 3 champ de 2 octets (champs de longueur), et au moins un élément dans le champ de liste de chiffrement (de la taille 3). donc, il faut être d'au moins 9 octets (longueur de données> = 9).

  • b [2] doit être 0x01

  • (type de message "ClientHello")

SSL 3.0 ou TLS 1.0, 1.1 et 1.2

+-------+------------------+------------------+--------+------
| 0x16  | 2 bytes version  |  2 bytes length  |  0x01  |  etc.
+-------+------------------+------------------+--------+------
  • b [0] == 0x16 (type de message "handshake SSL")

  • b [1] devrait être 0x03 (actuellement toute nouvelle version majeure, mais qui sait à l'avenir?)

  • b [5] doit être 0x01

  • (message de protocole d'établissement de liaison "HelloClient")

Pour référence, vous pouvez voir http://www.mozilla.org/projects /security/pki/nss/ssl/draft02.html et http://tools.ietf.org/html/rfc4346

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top