Использование SSL BIO на канале libssh2 - PullRequest
1 голос
/ 18 июня 2010

Я пишу небольшой ftp-проект для собственного удовольствия, который должен быть в состоянии сделать 4 вещи:

  1. подключается напрямую к ftp
  2. подключиться напрямую к FTP с SSL (оболочка)
  3. подключиться через туннель SSH к FTP
  4. подключиться через туннель SSH к FTP с SSL.

Я пишу свою программу на простом C (unix, в данном случае это не имеет значения), используя стандартные библиотеки для 1 и 2, используя libssh2 для 3 и 4 в дополнение к OpenSSL для 2 и 4.

Я могу заставить работать 1-3, но не 4. Вот где я нахожусь:

  1. сделано путем открытия сокета для хоста: порт, подключение, запись / чтение из сокета.
  2. выполняется путем открытия сокета для хоста: порт, подключение, запись «AUTH SSL», запуск объекта SSL с BIO из предыдущего сокета -> SSL_connect (), SSL_read (), SSL_write ().
  3. сделано путем открытия туннеля между целью и локальным хостом (хотя я не уверен, для чего я использую привязку локального хоста в моем подходе:)

что-то вроде:

test_ssh_channel = libssh2_channel_direct_tcpip_ex(test_ssh_session, "100.100.100.100", 21, "127.0.0.1", 21);

Затем я пишу / читаю в этот канал (libssh2_channel_read ()) - который, как я вижу, дает следующий поток: обычный текст -> отправить через ssh -> доставить простой текст к цели с хоста ssh. Для цели 3. это хорошо и делает работу.

Теперь, для 4. Я застрял, так как мне (пытаясь сделать это проще) нужно как-то превратить этот канал в сокет. Так что, как я вижу, у меня есть два варианта:

  • а. Сделайте псевдо-сокет и каждый раз мне нужно читать / писать, я чтение / запись с канала, отправить / извлечь его в сокет, и пусть SSL_connect (pseudo_socket) общаться с моим псевдо-сокетом, каждый раз принимая в чем то отправляет ssl_write, отправляет канал и наоборот.

или

  • б. установить буфер BIO (есть гораздо больше функций БИО, чем я могу обернуть мою голову вокруг; документация не была полностью полезно) и как-то читать / писать что.

В идеале я бы пошел на 2, по этой причине: поскольку мой проект написан на C, поддержка чтения / записи сокета при выполнении другого кода станет немного более сложной, чем я бы предпочел.

Однако б. дает проблему: я волнуюсь, как будет работать рукопожатие; в частности, я боюсь, что в итоге я получаю рукопожатие с localhost вместо удаленного, так сказать.

Подводя итог моему вопросу: Могу ли я через канал читать / писать в SSL (обернуть его оберткой), чтобы поток для 4. стал: обычный текст -> SSL (открытый текст) -> через ssh -> доставить SSL (открытый текст) на целевой хост с хоста ssh?

Это немного долго, но я надеюсь, что это было понятно. Если нет, пожалуйста, дайте мне знать, и я проясню. Из поиска в стеке и поиска в Google кажется, что у меня и у парня, работающего с MySQL, такая же проблема и ограниченные ответы.

ЛЮБОЙ ввод очень важен!

  • Джеймс

1 Ответ

2 голосов
/ 21 июня 2010

Да, вариант 2 - правильный путь. Создайте пару BIO с BIO_make_bio_pair() и назначьте их объекту SSL с помощью SSL_set_bio().

Затем вы читаете данные SSL зашифрованной стороны с помощью BIO_read() и записываете их в туннель libssh, читаете из туннеля libssh и пишете их с BIO_write().


Добавление:

Когда вы используете этот метод, ваш объект SSL не имеет собственный дескриптор файла - BIO заменяют дескриптор / сокет файла. Вместо чтения и записи из файлового дескриптора, OpenSSL будет читать и писать из предоставленных вами BIO.

BIO - это просто интерфейс, который находится между библиотекой OpenSSL и вашим собственным кодом. Это способ для вас реализовать фактическую доставку данных SSL зашифрованной стороны на другую сторону и обратно (вместо OpenSSL напрямую с использованием сокета).

Когда вы делаете BIO_read() в BIO, который вы указали как wbio - SSL_set_bio(), вы будете читать данные SSL с зашифрованной стороны, а затем должны будете отправить их на другую сторону самостоятельно (предположительно, используя некоторые libssh2 функция). Точно так же, когда вы получаете данные SSL зашифрованной стороны с другой стороны (опять же, из какой-то функции libssh2), вы закачиваете их в SSL, используя BIO_write() в BIO, который вы указали как rbio.

Возможно, эта иллюстрация поможет. Когда вы читаете и пишете из объекта SSL, OpenSSL будет просто читать и записывать из базового BIO, оставляя данные для дальнейшего использования:

+------+               +-----+               +-----+
| Your | SSL_write()   | SSL | BIO_read()    | BIO |
| code | ------------> |     | <------------ |     |
|      |               |     |               |     |
|      |               |     | BIO_write()   |     |
|      |               |     | ------------> |     |
+------+               +-----+               +-----+

+------+              +-----+               +-----+
| Your | SSL_read()   | SSL | BIO_read()    | BIO |
| code | <----------- |     | <------------ |     |
|      |              |     |               |     |
|      |              |     | BIO_write()   |     |
|      |              |     | ------------> |     |
+------+              +-----+               +-----+

(Обратите внимание, что SSL_write() может вызвать чтение из базового BIO и наоборот).

Когда в wbio есть данные, вы должны прочитать их и отправить на другую сторону:

+------+              +-----+
| Your | BIO_read()   | BIO |
| code | <----------- |     |
|      |              +-----+
|      |                           +---------+
|      | libssh2_channel_write()   | libssh2 |
|      | ------------------------> |         | -> (... to other side)
|      |                           +---------+
+------+

И наоборот, когда есть данные, доступные с другой стороны, вы должны прочитать их и передать в rbio:

+------+
| Your |                          +---------+
| code | libssh2_channel_read()   | libssh2 |
|      | <----------------------- |         | -> (... from other side)
|      |                          +---------+
|      |              +-----+
|      | BIO_write()  | BIO |
|      | -----------> |     |
|      |              +-----+
+------+
...