2010-12-09 3 views
2

J'ai un code hérité qui utilise OpenSSL pour la communication. Comme toute autre session, il effectue une poignée de main en utilisant les fonctions SSL et ensuite la communication cryptée sur TCP. Nous avons récemment changé notre code pour utiliser les ports d'achèvement d'E/S. La façon dont cela fonctionne est contraire à celle d'OpenSSL. Fondamentalement, j'ai du mal à faire migrer notre code de communication sécurisé de l'utilisation complète d'OpenSSL vers les sockets IOCP et le chiffrement OpenSSL.Ports d'achèvement d'E/S et OpenSSL

Quelqu'un a-t-il/quelqu'un at-il des références qui pourraient m'aider avec une telle tâche? Comment le handshaking TLS fonctionnerait-il sur IOCP?

Répondre

7

Pour utiliser OpenSSL pour le cryptage, mais faire votre propre socket IO, ce que vous faites essentiellement est de créer un BIO mémoire, que vous lire et d'écrire des données de socket en tant que devient disponible et attachez-le au contexte SSL.

Chaque fois que vous faites un appel SSL_write, vous suivez avec un appel à la mémoire BIO pour voir si elle a des données dans sa mémoire tampon de lecture, lu que et l'envoyer. Inversement, lorsque des données arrivent sur le socket via votre mécanisme de port d'achèvement io, vous l'écrivez dans BIO et appelez SSL_read pour lire les données. SSL_read peut renvoyer un code d'erreur indiquant son dans une poignée de main, ce qui signifie généralement qu'il a généré plus de données à écrire - que vous gérez en relisant la mémoire BIO.


Pour créer ma session SSL, je fais ceci:

// This creates a SSL session, and an in, and an out, memory bio and 
// attaches them to the ssl session. 
SSL* conn = SSL_new(ctx); 
BIO* bioIn = BIO_new(BIO_s_mem()); 
BIO* bioOut = BIO_new(BIO_s_mem()); 
SSL_set_bio(conn,bioIn,bioOut); 
// This tells the ssl session to start the negotiation. 
SSL_set_connect_state(conn); 

Comme je reçois des données de la couche réseau:

// buf contains len bytes read from the socket. 
BIO_write(bioIn,buf,len); 
SendPendingHandshakeData(); 
TryResendBufferedData(); // see below 
int cbPlainText; 
while(cbPlainText = SSL_read(ssl,&plaintext,sizeof(plaintext)) >0) 
{ 
    // Send the decoded data to the application 
    ProcessPlaintext(plaintext,cbPlaintext); 
} 

Comme je reçois des données de l'application à envoyer - vous devez vous préparer à l'échec de SSL_write car une prise de contact est en cours, auquel cas vous tamponnez les données et essayez de les envoyer à nouveau ultérieurement après avoir reçu des données.

if(SSL_write(conn,buf,len) < 0) 
{ 
    StoreDataForSendingLater(buf,len); 
} 
SendPendingHandshakeData(); 

Et SendPendingHandshakeData envoie toutes les données (handshake ou texte chiffré) que SSL doit envoyer.

while(cbPending = BIO_ctrl_pending(bioOut)) 
{ 
    int len = BIO_read(bioOut,buf,sizeof(buf)); 
    SendDataViaSocket(buf,len); // you fill this in here. 
} 

C'est le processus en un mot. Les exemples de code ne sont pas complets car je devais les extraire d'une bibliothèque beaucoup plus grande, mais je crois qu'ils sont suffisants pour en commencer un avec cette utilisation de SSL. Dans le code réel, lorsque SSL_read/écriture/BIO_read/écriture échouent, il est probablement préférable d'appeler SSL_get_error et de décider quoi faire en fonction du résultat: SSL_ERROR_WANT_READ est important et signifie que vous ne pourriez pas SSL_write plus de données, car il a besoin de vous lire et envoyer les données en attente dans le bioOut BIO en premier.

+0

Ceci est un excellent exemple. Dans un cas où je suis le serveur, est-ce que je remplacerais simplement l'appel SSL_set_connect_state() pour l'appel SSL_set_accept_state()? – MarkP

+0

Je n'ai travaillé qu'avec des sockets côté client et OpenSSL, mais d'après ce que j'ai compris de la documentation, cela devrait être aussi simple. –

+0

Très bien. Aussi, pourquoi est-il prudent d'appeler SendPendingHandshakeData() partout? Je suppose que la poignée de main ne se produit qu'une seule fois, au début de la session. Ou arrive-t-il chaque fois qu'un paquet est envoyé? – MarkP

0

Vous devriez regarder dans Boost.Asio

+0

Est-ce que 'Asio' OpenSSL de soutien? – Gabe

+0

Oui, il y a quelques exemples dans le lien que j'ai posté. –

+0

Même s'il ne répond pas tout à fait à la question, boost :: asio a assez d'awesomeness à l'intérieur pour mériter un +1. –