Установка защищённого соединения
Прежде чем создавать защищённый канал, нужно установить обычное исходящее TCP-соединение:
sock.protocol=PL_SOCK_PROTOCOL_TCP 'Tibbo programmable devices do not support TLS over UDP
sock.targetip="192.168.1.1" 'Replace "192.168.1.1" with the target server's IP address
sock.targetport=443 'Replace 443 with the desired port
sock.txbuffrq(2) 'While not strictly necessary, increasing the TX and RX
sock.rxbuffrq(2) 'buffers to 2 significantly improves performance
sys.buffalloc 'Only needed if manually setting buffer sizes,
'including sock.tlsbuffrq
sock.connect()
Прежде чем двигаться дальше, стоит убедиться, что обычное незашифрованное соединение установлено. Подробнее см. Проверка состояния соединения. Если соединения ещё нет, создать защищённый канал не удастся.
Далее вызовите метод sock.tlsinit, чтобы инициализировать TLS-соединение (это можно сделать и до установки исходящего TCP-соединения). Здесь в дело вступает сертификат шифрования, добавленный в проект: sock.tlsinit разбирает сертификат и, если смещение указано верно, загружает его в память.
romfile.open("example.cer") 'Replace "example.cer" with the name of the certificate
'included in your project
sock.tlsinit(romfile.offset)
Поскольку одновременно можно поддерживать только одно зашифрованное соединение, попытка установить новое защищённое соединение при уже существующем завершится неудачей. Свойство только чтение sock.tlscurrentnum показывает, на каком сокете (если такой есть) инициализирован TLS (то есть sock.tlsinit был успешно вызван). Если ни один сокет не настроен на TLS, свойство возвращает 255.
Чтобы убедиться, что sock.tlsinit выполнен, проверьте код состояния, который возвращает этот метод:
select case sock.tlsinit(romfile.offset)
case PL_TLS_SUCCESS:
'Initialization was completed successfully
case PL_TLS_REJECTED
'Initialization attempt was rejected
'(TLS has already been initialized on the current socket)
case PL_TLS_ERROR_IN_USE
'TLS resources tied to another socket
case PL_TLS_ERROR_CERT
'Certificate error
'(not a X.509 certificate or not a supported cypher suite)
case PL_TLS_ERROR_NO_BUFF
'Insufficient memory
case PL_TLS_ERROR_INTERNAL
'Unspecified internal error — please contact Tibbo support
end select
После того как TLS инициализирован и установлено исходящее TCP-соединение, можно вызвать метод sock.tlshandshake, чтобы включить шифрование на выбранном сокете. Метод принимает один параметр - строку с полным доменным именем нужного удалённого сервера (то есть всё, что стоит после "https://" до первой косой черты). Если сверять имя сервера с сертификатом не нужно, передайте пустую строку; это удобно при подключении напрямую по IP-адресу.
Попытка вызвать sock.tlshandshake на сокете, отличном от того, на котором выполнялся sock.tlsinit, завершится неудачей с возвратом PL_TLS_ERROR_IN_USE.
Кроме того, вызов sock.tlshandshake вернёт PL_TLS_REJECTED в следующих случаях:
- Выбран не протокол TCP (sock.protocol <> PL_SOCK_PROTOCOL_TCP)
- TCP-соединение не является исходящим (sock.state <> PL_SST_EST_AOPENED)
- sock.tlsinit не выполнялся ни на одном сокете (sock.tlscurrentnum = 255)
select case sock.tlshandshake("your.example.com")
'Replace "your.example.com" with the domain name of the desired server
case PL_TLS_SUCCESS:
'All good!
case PL_TLS_REJECTED:
'Many possible reasons (see above)
case PL_TLS_ERROR_IN_USE:
'TLS is already happening on some other socket
end select
Даже если sock.tlshandshake вернул PL_TLS_SUCCESS, создание защищённого соединения всё равно может завершиться неудачей по ряду причин, описанных ниже. Окончательным и достоверным признаком успешной установки TLS-канала служит переход sock.state в PL_SST_EST_TLS. Как всегда, переходы sock.state асинхронны, поэтому реагируйте в обработчике on_sock_event и предусматривайте возможный тайм-аут (например, отсчитывая время в обработчике события on_sys_timer).
Устранение неполадок при рукопожатии
Если после возврата PL_TLS_SUCCESS из sock.tlshandshake TLS-канал не устанавливается, причиной могут быть следующие обстоятельства:
| Возможная проблема | Что проверить |
| В качестве параметра sock.tlshandshake передан недопустимый домен. |
|
| Сертификат, предъявленный удалённому узлу, содержит ошибку. | |
| Данные, полученные от удалённого узла во время рукопожатия, содержат ошибку. |
|
| Дополнительные поля в сертификате увеличили требования к памяти (в WM2000 такой проблемы не будет). При диагностике с помощью плагина SSL Server Terminal в IO Ninja в журнале сервера появится сообщение "decryption error". |
|
Дополнительные замечания
После выполнения sock.tlshandshake ваш код не должен использовать на этом сокете sock.setdata, sock.getdata и sock.rxclear (sock.txclear в списке нет, потому что он не работает, когда сокет не простаивает). В режиме TLS TiOS управляет данными, проходящими через буферы передачи и приёма, автоматически. Попытки "вручную" извлечь что-либо из буфера приёма (или очистить его) либо поместить что-либо в буфер передачи нарушат поток данных, которым управляет встроенный в TiOS механизм TLS, и защищённое соединение станет непригодным для работы.
Чтобы не мешать работе TLS, также НЕ включайте:
Кроме того, после перехода к защищённому обмену некоторые свойства и методы объекта sock "перестанут иметь смысл". Это опять же следствие автоматической работы с буферами передачи и приёма в режиме TLS и того, что зашифрованные данные отправляются и принимаются блоками. Например, один байт данных, помещённый в буфер TLS TX, может превратиться в блок зашифрованных данных размером 2048 байт в буфере передачи! Свойства и методы, которые "перестанут иметь смысл": sock.newtxlen, sock.peekdata, sock.rxlen, sock.txfree и sock.txlen.
После успешного рукопожатия устройство перейдёт в состояние PL_SST_EST_TLS свойства sock.state, означающее, что канал установлен. Теперь можно отправлять и принимать зашифрованные данные.