2015-10-28 1 views
0

J'ai un problème étrange avec OpenSSL en C#. Faits: J'ai programmé un wrapper pour C# qui fonctionne complètement bien, il pourrait se connecter à d'autres serveurs SSL, ou accepter les connexions des clients SSL. Mon wrapper n'utilise que la mémoire BIO. Chaque fois que je connecte le MEM BIO à l'intérieur et les sorties de tout type de socket poignée de main est réussie, le transfert de données est de travail, donc le problème n'est pas dans l'emballage.Échec de la prise de contact OpenSSL avec deux sessions et mémoire directement connectée BIO's C#

J'ai fait deux programmes avec ce wrapper, un client et un serveur, ils rendent la session ssl, et quand j'essaye d'envoyer des données du serveur au client (ou de manière opposée) et l'autre côté lui fait écho retour à l'expéditeur pour une raison quelconque le trafic de données est très lent (max 20kB/s même en boucle locale, si j'essaye d'envoyer avec plus de vitesse comme pumping plus de données dans le SSL_read() puis avec TLS sur TCP il y a d'énormes retards, avec DTLS sur UDP il y a parfois 75% de perte de paquets), donc j'ai décidé de comparer l'OpenSSL avec l'encapsuleur, parce que certaines méthodes ou mauvais paramètres peuvent ralentir l'exécution.

Mon idée était d'initier deux contextes SSL dans un programme, un client et un serveur, de connecter les BIO mémoire les uns aux autres (RX-TX TX-RX), et de commencer une négociation. Je ne parviens tout simplement pas à les faire finir le handshaking avec succès!

Avec DTLS1 après ClientHello, le serveur commence à réagir avec les données ServerHello et Cert dans 4 paquets (3x256 octets + 145), mais après le premier paquet des alertes de clients:

After writing to CLIENT (packet: 2): 22016:error:14102044:SSL routines:dtls1_read_bytes:internal error:.\ssl\d1_pkt.c:1370: 
After writing to CLIENT (packet: 3): 22016:error:14102044:SSL routines:dtls1_read_bytes:internal error:.\ssl\d1_pkt.c:1370: 
After writing to CLIENT (packet: 4): 22016:error:14102044:SSL routines:dtls1_read_bytes:internal error:.\ssl\d1_pkt.c:1370: 
After writing to CLIENT (packet: 5): 22016:error:14102044:SSL routines:dtls1_read_bytes:internal error:.\ssl\d1_pkt.c:1370: 

Le flux de paquets entre le deux sessions sont les suivantes:

Client -> 178 -> Server 
Server -> 256 -> Client 
Server -> 256 -> Client 
Server -> 256 -> Client 
Server -> 145 -> Client 
Client -> 15 -> Server 

J'ai analysé ces paquets (après vidage de fichier) avec Wireshark, et tout semble OK (cette analyse n'est pas des paquets ci-dessus, mais même la reproduction du problème): http://reset.tor.hu/ssl/sima/programom_dtls1.txt

Après ce que je reçois plus d'erreurs:

After writing to SERVER (packet: 5): 22016:error:141020E5:SSL routines:dtls1_read_bytes:ssl handshake failure:.\ssl\d1_pkt.c:819: 
Before writing to SERVER (packet: 6): 22016:error:140FD10F:SSL routines:DTLS1_GET_MESSAGE_FRAGMENT:bad length:.\ssl\d1_both.c:892: 
After writing to SERVER (packet: 6): 22016:error:14102417:SSL routines:dtls1_read_bytes:sslv3 alert illegal parameter:.\ssl\d1_pkt.c:1200:SSL alert number 47 
22016:error:141020E5:SSL routines:dtls1_read_bytes:ssl handshake failure:.\ssl\d1_pkt.c:819: 

Ma seule idée utile était de déboguer ce problème pour vider les paquets vers des fichiers juste après qu'ils ont été lus à partir du BIO et juste avant qu'ils ne soient écrites dans le BIO dans l'autre session, mais je n'ai trouvé aucune différence dans le contenu après la comparaison des octets, et la séquence de paquets était OK, aussi.

décharges de fichiers sont ici: http://reset.tor.hu/ssl/y/direct_bio_error/

Je ne pouvais pas imaginer que ce pourrait être le problème parce qu'ils ont jamais fini poignée de main sans échec, j'ai donc décidé d'ajouter deux sockets UDP à ce programme, et connecter les prises aux BIO et les uns aux autres, et sans surprise la poignée de main a été réussie pour la première fois.

décharges de fichiers sont ici: http://reset.tor.hu/ssl/y/socket_ok/

Comme il est visible, il y a une différence de rien dans le contenu du fichier ou les séquences de paquets.

Alors pourquoi ne travaillent-ils pas avec BIO directement connecté ?!

Vous pouvez voir le programme de production de l'erreur et le fonctionnement normal dans cette vidéo: https://www.youtube.com/watch?v=4crbSz6JMMY

Ma seule idée était C# pour une raison quelconque mélange de la méthode appelle dans le temps, mais je ne suis pas utiliser un filetage! Le code non géré appelle un rappel pour lire BIO, j'ai lu BIO dans mon tampon, j'appelle une autre méthode qui écrit le tampon dans le BIO et appelle SSL_read() dans le code non managé, pour utiliser les données dans le BIO. Et c'est exactement dans l'autre sens. Si je n'utilise pas le tampon, mais les sockets à la place ça marche. Qu'est-ce que les prises peuvent faire pour que ça marche?

J'ai même essayé de mettre Thread.Sleep (100) entre les écritures de BIO, mais n'a pas aidé, réellement sur 140ms OpenSSL s'est écrasé (mais avec des douilles cela a fonctionné même avec 1000ms, encore plus bizarre).

Quel pourrait être le problème et la solution pour le BIO direct et le problème de trafic lent?

Merci pour les réponses à l'avance!

Répondre

0

Ok, en fait, il semble que j'ai juste résolu le problème Direct-Memory-BIO-Handshake.

Il est suggéré d'appeler SSL_read() après BIO_write(), sinon OpenSSL ne vérifie pas les données du BIO et READ ne traitera pas, donc presque à chaque fois que les gens l'utilisent directement après avoir écrit à BIO.

Si l'on configuré le contexte OpenSSL en tant que client puis un ne doit pas utiliserSSL_read() après BIO_write() directement jusqu'à handshaking pas fini!

Si OpenSSL est utilisé avec prise (même avec sa mémoire bio), il travaille si nous utilisons SSL_read() directement après BIO_write(), mais avec connexion BIO directe entre deux sessions non. Au moins en tant que code non géré en C#!

La méthode d'écriture de BIO qui fonctionne bien est la suivante:

public bool BIO_Write(byte[] data) 
    { 
     if (Inited & data.Length > 0) 
     { 
      Wrapper.BIO_write(BIOR, data, data.Length); 
      if (isServer(SSL_method)) 
      { 
       // For SERVER MODE 
       if (Wrapper.SSL_is_init_finished(SSL)) 
       { 
        readFromSSL(); 
       } 
       else 
       { 
        Wrapper.SSL_do_handshake(SSL); 
       }    
      } 
      else 
      { 
       // For CLIENT MODE 
       if (Wrapper.SSL_is_init_finished(SSL)) 
       { 
        readFromSSL(); 
       } 
       else 
       { 
        // It is extremely important to call the SSL_do_handshake() 
        // only if SSL_want() returns 3, otherwise OpenSSL will 
        // throw a FATAL ERROR and crash with direct BIO connection 
        // return value 3 is SSL_ERROR_WANT_WRITE 
        if (Wrapper.SSL_want(SSL) == 3) 
        { 
         Wrapper.SSL_do_handshake(SSL); 
        } 
       } 
      } 
      return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 

J'espère que cela aidera quelqu'un!