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.
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
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. –
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