eSSL — SSL сертификаты для встраиваемых систем

В наше время сетевые технологии развиваются столь стремительно что еще недавно казавшийся бредовым лозунг "интернет в каждом холодильнике" уже не кажется фантастикой. Но вместе с тем начинают становиться актуальными вопросы безопасности встраиваемых устройств имеющих WEB интерфейс с выходом в локальную и, не дай бог, в глобальную сеть. SSL технология призвана помочь этому позволяя работать с WEB интерфейсом по протоколу HTTPS, но встраиваемые системы имеют здесь свои особенности.

Немого общей имформации об SSL


Технология SSL позволяет шифровать трафик между двумя устройствами. Вы, наверное знаете, что SSL сертификаты выдаются web-сайтам и приязываются на домены или поддомены. Сертификаты выдаются доверенными центрами сертификации (Certification Authority) и подписываются электронными подписями. Сертификаты подтверждаются в браузерах путем проверки цепочки сертификатов (Certification Path), корневые сертификаты этих центров уже распространяются вместе с дистрибутивами основных браузеров и такая проверка происходит незаметно для пользователя. В случае, если доверенный корневой сертификат не найден браузером, пользователю выдается страничка с предупреждением о том, что соединение с сервером не является безопасным.

Проблема встраиваемых систем в том, что,
  • во-первых, это не web-сайт в общем понимании этого слова (вспомните, например, веб-интерфейс Wi-Fi роутера), в момент выпуска изделия он не имеет окончательного IP адреса, и еще менее вероятно чтобы он имел какой то домен.
  • во-вторых, конечный пользователь может сменить и IP, и домен, если таковой был, хотя бы в целях все той же безопастности.
  • в-третьих, покупать сертификат довольно дорого, а вопрос снижения себестоимости стоит всегда.

Как же решать эти проблемы?

eSSL — embedded Secure Socket Layer


Дальше я представлю на Ваш суд результаты моих исследований данного вопроса проверенные опытным путем. Термин eSSL пришел мне в голову в процессе написания этой статьи, так что любые упоминания прошу употреблять вместе со ссылкой на embedders.org.
Итак, освещу немного важные аспекты строения сертификатов, которые позволяют использовать их нужным нам способом. Любой сертификат представляет собой совокупность строковых полей подписанную закрытым ключем (private key). Сертификат также содержит в себе открытый ключ для проверки подлинности данных содержащихся в этих строковых полях. Перечень полей определен в формате Х.509 v3 и описан в документе RFC 5280(это последняя на данный момент редакция документа, до этого действовал RFC 3280). Сертификат содержит поле commomName которое описывает имя субъекта сертификации, обычно оно совпадает с доменом веб-сайта для которого выпущен сертификат, но в стандарте нет никаких запретов на то что будет вписано в эту строку, например, строка "Вася Пупкин" будет так же валидна для этого поля с точки зрения стандарта — это первый аспект. Но веб-браузеры проверяют именно это поле на соответствие с именем сайта который предъявляет сертификат. К счастью для нас в формате X509 v3 определены дополнительные расширения, одно из которых subjectAltName, которое позволяет добавить идентификаторы, связанные с основным именем субъекта сертификации (commomName). Такими идентификаторами могут быть:
  • Адрес электронной почты
  • DNS
  • IP адрес
  • и URI

и это второй и, пожалуй, наиболее важный аспект строения сертификатов 3й версии стандарта. Дело в том что таких идентификаторов можно добавить несколько, т.е. можно вписать несколько IP адресов для которых будет валиден выпущенный сертификат. А это и есть то что нам нужно в случае если некое устройство имеет два Ethernet интерфейса для работы в разных под-сетях, да еще и возможность выхода в сеть через различные типы модемов, если соединение будет по PPP, то это будет третий интерфейс со своим IP адресом. Опытным путем мною был установлен один важный момент в назначении альтернативных IP адресов. Браузеры Internet Explorer и FireFox по разному производят проверку альтернативных имен. FireFox сверяет адрес который указан в идентификаторе IP, а IE — сверяет адрес с идентификатором DNS. Поэтому, для осуществления проверки сертификата в обоих браузерах, каждый необходимый IP адрес должен быть указан и как IP и как DNS. О том как это сделать будет рассказано дальше.

Сценарий использования SSL во встраиваемых системах


Приведу для примера один из возможных сценариев использования сертификатов во встраиваемых системах. Этот сценарий не требует покупки сертификатов, но имеет ограничения в использовании. Итак,
  1. Нам потребуется создать самоподписанный корневой сертификат, в этом случае мы станем сами себе центром сертификации.
  2. Далее нам нужно создать сертификат для нашего web-интерфейса и подписать его корневым сертификатом, созданным на первом шаге.
  3. Этот сертификат мы помещаем в память  нашей встраиваемой системы где его сможет найти встроенный веб-сервер.
  4. Всем пользователям веб-интерфейса мы должны выдать наш корневой сертификат, но не приватный ключ.
  5. Пользователи веб-интерфейса должны импортировать наш корневой сертификат в свои веб-браузеры на всех компьютерах с которых предполагается вход на веб-интерфейс.

Особо отмечу, что этот сценарий не является безопасным, подобный способ используют производители роутеров, а умные хакеры извлекают ключи из прошивок и складывают в базу данных code.google.com/p/littleblackbox. Этот способ не является и удобным, потому что мы должны передать корневой сертификат конечному пользователю. А от нас еще и потребуется хранить корневой сертификат и приватный ключ к нему в безопасном месте. В идеале обе этих функции обеспечивает один из доверенных центров сертификации, но за это они взымают плату.
Далее я расскажу, как на практике реализовать предложенный сценарий. Все действия будут производиться на компьютере под управлением ОС Linux (Debian) и программы openssl.

Создание корневого сертификата


  1. Установить openssl-1.0
  2. Отредактировать файл '/etc/ssl/openssl.cnf' (а лучше скопировать его себе в домашнюю папку) изменив там следующие строки:

    [ CA_default ]
    
    dir		= .		# Where everything is kept
    
    unique_subject	= no	# Set to 'no' to allow creation of
                            # several ctificates with same subject.
    		

    Здесь dir — это базовый каталог в котором будет располагаться наш собственный Центр Сертификации (Certificate Authority). Создаем его в текущем каталоге.
    Т.к. наши устройства могут иметь одинаковые имена (параметр commonName при создании сертификата), по этому, параметром unique_subject, мы разрешаем создавать много сертификатов для одного субъекта.
    Зададим длину ключа в 2048 (а можно и в 4096) бит.
    [ req ]
    default_bits		= 2048
    		

    Далее можно указать параметры по умолчанию чтобы не вводить их каждый раз в ручную, хотя, для корневого сертификата их нужно будет вводить только один раз, если Вы не собираетесь делать сотню-другую корневых сертификатов.
    [ req_distinguished_name ]
    countryName			= Country Name (2 letter code)
    countryName_default		= RU
    countryName_min			= 2
    countryName_max			= 2
    
    stateOrProvinceName		= State or Province Name (full name)
    stateOrProvinceName_default	= Saint-Petersburg
    
    localityName			= Locality Name (eg, city)
    localityName_default		= Saint-Petersburg
    
    0.organizationName		= Organization Name (eg, company)
    0.organizationName_default	= My Cool Company
    
    # we can do this but it is not needed normally :-)
    #1.organizationName		= Second Organization Name (eg, company)
    #1.organizationName_default	= World Wide Web Pty Ltd
    
    organizationalUnitName		= Organizational Unit Name (eg, section)
    #organizationalUnitName_default	=
    
    commonName			= Common Name (eg, YOUR name)
    commonName_default		= My Device
    commonName_max			= 64
    

  3. Создать каталог my-certs где будет наш Центр Сертификации. Создать подкаталог conf и поместить туда наш файл конфигурации.
  4. Отредактировать в файле '/usr/lib/ssl/misc/CA.pl' следующие строки:
    $SSLEAY_CONFIG="-config /home/user/my-certs/conf/openssl.cnf";
    $CADAYS="-days 3650";   # 10 years
    $CATOP=".";
    		

    Здесь $SSLEAY_CONFIG зазадает путь к фаилу конфигурации.
    $CADAYS указывает сколько дней будет действителен корневой сертификат
    $CATOP указывает в каком каталоге будем работать. Этот параметр должен совпадать с тем что мы указали в dir в файле конфигурации на шаге 2.
  5. Выполнить команду
    /usr/lib/ssl/misc/CA.pl -newca
    

    Она создаст необходимую структуру каталогов и корневой сертификат, и подпишет его самим собой.
    По запросу необходимо ввести пароль для будущего корневого сертификата и затем повторить его
    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:
    

  6. Ввести неоходимую информацию о вас как о Центре Сертификации: страну, регион, город, фирму. В поле 'common Name' следует ввести что-то типа 'My Device root Certificate', эта строка будет в дальнейшем показываться в пути проверки сертификата в браузере пользователя. Чтобы просмотреть содержимое только что созданного сертификата выполните команду (тут в примере сертификат с ключем 1024 бит)
    openssl x509 -in cacert.pem -noout -text
    
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number:
                 d9:98:4f:55:e0:bb:b3:3c
            Signature Algorithm: sha1WithRSAEncryption
            Issuer: C=RU, ST=Saint-Petersburg, O=My Cool Company, CN=My Device root Certificate
            Validity
                 Not Before: Oct 11 12:16:26 2011 GMT
                 Not After : Oct  8 12:16:26 2021 GMT
             Subject: C=RU, ST=Saint-Petersburg, O=My Cool Company, CN=My Device root Certificate
             Subject Public Key Info:
                 Public Key Algorithm: rsaEncryption
                      Public-Key: (1024 bit)
                      Modulus:
                          00:d1:d1:0a:11:a3:1e:67:2b:d2:39:3e:ea:bf:44:
                          04:f9:2a:ae:c4:37:a2:76:8b:fc:de:6c:04:5a:56:
                          35:0b:12:8e:e6:31:62:5a:88:b4:53:a5:bf:9f:63:
                          ea:6d:33:f9:4a:84:a5:8b:b1:f3:0b:9e:56:f8:27:
                          0d:8c:be:1d:76:be:6c:e5:c9:f3:f1:b0:cd:df:79:
                          b4:0b:05:db:25:15:c1:e5:b3:08:17:af:67:e9:be:
                          44:a2:ce:ed:9a:6c:16:bb:f6:8c:73:ab:dd:86:5a:
                          82:73:6c:5e:03:fa:6e:8e:06:07:dd:8e:fb:95:51:
                          16:4b:91:87:be:15:9e:12:21
                     Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Subject Key Identifier:
                    1F:1С:A6:43:A2:49:E7:16:49:EC:FD:73:71:72:D7:7F:24:6D:AC:17
                X509v3 Authority Key Identifier:
                    keyid:1F:1С:A6:43:A2:49:E7:16:49:EC:FD:73:71:72:D7:7F:24:6D:AC:17
    
               X509v3 Basic Constraints:
                   CA:TRUE
        Signature Algorithm: sha1WithRSAEncryption
            60:f2:cf:c7:52:11:83:c7:ea:b7:ae:68:8a:63:7a:89:5b:d6:
            4e:ae:ba:0d:9d:a3:e6:86:07:db:54:77:59:b1:f9:dc:38:bd:
            a2:31:b6:18:80:80:3d:e1:20:13:23:28:26:b8:b0:aa:4f:a8:
            f7:92:89:13:2a:48:62:29:fb:3c:b7:ab:23:cb:97:ae:7c:21:
           15:8e:23:e3:13:a1:e1:0d:85:dc:d0:8d:f7:fc:a5:60:0e:bc:
           5d:ea:31:d1:b4:ac:f6:24:b2:7e:4e:27:88:67:16:94:6e:5d:
           4b:b4:ef:fa:8a:49:71:23:62:81:78:2c:03:a3:3d:ae:c9:7b:
           5c:f8
    

  7. Затем сделаем RSA ключ без пароля
    ~/my-certs$ openssl rsa -in private/cakey.pem -out private/ca.key
    Enter pass phrase for private/cakey.pem:
    writing RSA key
    

    Его нужно указать в файле конфигурации(/home/user/my-certs/conf/openssl.cnf), тогда при создании пользовательских сертификатов не нужно будет каждый раз вводить пароль для корневого сертификата.
    private_key	= $dir/private/ca.key	# The private key
    

  8. Создадим сертификат в формате x509
    ~/my-certs$ openssl x509 -in cacert.pem -out ca.crt
    

    Его нужно указать в файле конфигурации, тогда при создании пользовательских сертификатов не нужно будет каждый раз вводить пароль для корневого сертификата.
    certificate	= $dir/ca.crt	 	# The CA certificate
    

  9. В результате у нас будет 4 файла
    private/ca.key
    private/cakey.pem
    ca.crt
    cacert.pem
    

    Эти файлы надо "беречь как зеницу ока" ибо ими будут подписываться все сертификаты для конечных пользователей. Но файл ca.crt будет передаваться конечным пользователям для импорта в браузеры.

Сертификаты для устройств


Теперь нам нужно создать сертификат конечного пользователя или сервера и подписать его корневым сертификатом, что мы создали в предыдущем разделе. Основная проблема для меня была в том, что мое устройство имеет несколько сетевых интерфейсов, которые подключаются в разные сети и, соответственно, имеют разные IP адреса.
  1. Отредактируем наш файл конфигурации openssl.cnf и добавим в конец секции [ usr_cert ] и перед секцией [ v3_req ] следующие, пожалуй, самые важные строки, которые будут решать наши проблемы.

    subjectAltName=@alt_names
    
    [alt_names]
    # Имена. Можно указать хоть сколько, главное чтобы цифры после точки были разными.
    IP.0 = 192.168.10.1
    IP.1 = 192.168.1.1
    DNS.0 = 192.168.10.1
    DNS.1 = 192.168.1.1
    

    Здесь добавляются альтернативные имена которые появились в расширениях версии v3 стандарта x509 и могут быть DNS именем, IP адресом или URI адресом. Их может быть несколько, главное, чтобы отличалась цифра после точки. Опытным путем я установил что FireFox проглатывает имена IP, а IE8 — имена DNS. По этому, нужные нам IP адреса нужно продублировать  как IP для FireFox и как DNS для IE8, если, конечно, мы хотим работать и в IE, и в FireFox-е.
  2. Теперь можно создавать сертификаты. Тут нужно выполнять последовательность вызовов openssl с разными параметрами, чтобы упростить себе жизнь, я написал следующий простой скрипт:
    #!/bin/bash
    
    echo "*** Create request for sign ***"
    openssl req -config conf/openssl.cnf -new -keyout certs/$1.pem -out tmp.pem
    let ret=$?
    if let "$ret!=0"
    then
    	rm tmp.pem	
    	echo $ret
    exit 1
    fi
    echo "*** Create RSA key without password ***"
    openssl rsa -in certs/$1.pem -out certs/$1.key
    let ret=$?
    if let "$ret!=0"
    then
    	rm tmp.pem
    	echo $ret
    exit 1
    fi
    echo "*** Sign certificate by our own trusted key ***"
    openssl ca -config conf/openssl.cnf -policy policy_anything -out certs/$1.pem -infiles tmp.pem
    let ret=$?
    if let "$ret!=0"
    then
    	rm tmp.pem
    	echo $ret
    exit 1
    fi
    rm tmp.pem
    echo "*** Create certificate ***"
    openssl x509 -in certs/$1.pem -out certs/$1.crt
    let ret=$?
    if let "$ret!=0"
    then
    	echo $ret
    exit 1
    fi
    

    При запуске ему нужно передавать как параметр имя нового сертификата, например
    newcert.sh device
    

    Такой вызов создаст 2 файла device.crt и device.key, т.е. сертификат и ключ к нему. Во время выполнения скрипта будут заданы вопросы о пароле для нового сертификата, а также стране, городе, фирме для кого выпускается сертификат. В поле commonName можно указать любую строку, например My cool device, в обычной практике сюда записывается домен для которого выпускается сертификат, но мы записываем IP адреса (и домены) в раздере альтернативных имен, так что браузеры не ругаются страшными словами, а при просмотре сертификата показывают красивый путь проверки.

Как всё это применять?


Итак, мы создали 2 вида сертификатов, корневой сертификат и сертификат пользователя. Корневой сертификат, как правило, создается один раз и в дальнейшем используется для подписи пользовательских сертификатов, которые мы раздаем пользователям, т.е. помещаем на наши девайсы. Разберемся, как их применять.
Сертификат пользователя и ключ к нему нужно поместить на целевое устройство, у меня это некая плата с ARM контроллером и Linux-ом на борту. Не буду описывать этот процесс, т.к. он зависит от WEBсервера, что у нас там установлен.
А вот корневой сертификат нужно импортировать как корневой сертификат доверенного центра сертификации в каждый браузер пользователя. Только в этом случае браузер не будет показывать  предупреждения при заходе на страничку Вашего embedded WEB-сервера.

Импорт корневого сертификата в FireFox 6(Linux)


В FireFox 6 это делается черех меню Preferences -> Encryption -> View Certificates, выбираем вкладку Authorities.

Далее нажимаем Import и открываем файл нашего корневого сертификата ca.crt, на вопрос об использовании, ставим галочку на идентификацию WEB-серверов.

И мы можем лицезреть наш сертификат в списке доверенных центров


Импорт корневого сертификата в IE8 (Windows 7 64bit)


В меню Пуск в строке поиска наберите certmgr и нажмите комбинацию клавиш Ctrl+Shift+Enter, ответьте утвердительно на запрос прав администратора. У Вас запустится менеджер сертификатов.
Дважды кликните на разделе Trusted Root Certification Authorities
Кликните правой кнопкой мыши на Certificates -> All Tasks -> Import...

Запустится мастер импорта сертификатов, следуйте его инструкциям и в качестве сертификата укажите ca.crt. Если в результате получите ошибку

То поправьте ключ в реестре HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\Root\ProtectedRoots\Flags установите его в 0 и перезапустите менеджер сертификатов.

Заключение


Мы рассмотрели некоторые возможности SSL сертификатов позволяющие идентифицировать систему имеющую несколько IP адресов и/или Доменных имен, а так же рассмотрели простейший сценарий применения сертификатов во встраиваемых системах. Можно ли улучшить этот сценарий? Конечно можно. Например можно сделать так чтобы корневой сертификат генерировался прямо на устройстве и отдавался пользователю по запросу, например на USB Stick. В этом случае кража корневого сертификата не повлечет за собой опастность для подобных устройств у других покупателей. Применение самоподписанных сертификатов, безусловно, не является наилучшей практикой, но иногда для производителей встраиваемых систем это бывает единственный способ обеспечить минимальную безопастность своих устройств.
Часть информации относящуюся к сертификатам пользователей можно использовать и при покупке сертификатов подписываемых доверенными центрами сертификации. В этом случае обеспечивается наивысший уровень безопастности который может обеспечить технология SSL.

Использованные матриалы:


Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 2

    +2
    «Любой сертификат представляет собой совокупность строковых полей зашифрованную закрытым ключем (private key). Открытый ключ для расшифровки уже содержится в каждом сертификате.»
    У вас тут ошибка. Поправьте, пожалуйста. Закрытым ключом расшифровывают то, что зашифровано открытым ключом, либо подписывают исходящее сообщение перед шифрованием.

    При выдаче сертификат подписывается закрытым ключом CA.
      0
      Спасибо, поправил

      «Любой сертификат представляет собой совокупность строковых полей подписанную закрытым ключем (private key). Сертификат также содержит в себе открытый ключ для проверки подлинности данных содержащихся в этих строковых полях.»

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое