Программно создайте сертификат X509 с помощью OpenSSL
-
05-07-2019 - |
Вопрос
У меня есть приложение на C / C ++, и мне нужно создать сертификат X509 pem, содержащий как открытый, так и закрытый ключ.Сертификат может быть самоподписанным или неподписанным, не имеет значения.
Я хочу сделать это внутри приложения, а не из командной строки.
Какие функции OpenSSL сделают это за меня?Любой пример кода - это бонус!
Решение
Сначала вам необходимо ознакомиться с терминологией и механизмами. Р>
Сертификат X.509 по определению не включает закрытый ключ. Вместо этого это версия открытого ключа, подписанная СА (вместе с любыми атрибутами, которые СА помещает в подпись). Формат PEM на самом деле поддерживает только раздельное хранение ключа и сертификата, хотя вы можете затем объединить их.
В любом случае вам нужно будет вызвать более 20 различных функций API OpenSSL для создания ключа и самозаверяющего сертификата. Пример приведен в самом источнике OpenSSL, в демки / x509 / mkcert.c
Более подробный ответ см. в объяснении Натана Османа ниже.
Другие советы
Я понимаю, что это очень поздний (и длинный) ответ.Но, учитывая, насколько хорошо этот вопрос ранжируется в результатах поисковой системы, я подумал, что, возможно, стоит написать достойный ответ на него.
Многое из того, что вы прочтете ниже, заимствовано из эта демо-версия и документы OpenSSL.Приведенный ниже код применим как к C, так и к C++.
Прежде чем мы сможем на самом деле создать сертификат, нам нужно создать закрытый ключ.OpenSSL предоставляет EVP_PKEY
структура для хранения независимого от алгоритма закрытого ключа в памяти.Эта структура объявлена в openssl/evp.h
но включается в openssl/x509.h
(который нам понадобится позже), так что на самом деле вам не нужно явно включать заголовок.
Для того, чтобы выделить EVP_PKEY
структуру, мы используем EVP_PKEY_new
:
EVP_PKEY * pkey;
pkey = EVP_PKEY_new();
Существует также соответствующая функция для освобождения структуры - EVP_PKEY_free
- который принимает один аргумент:тот самый EVP_PKEY
структура, инициализированная выше.
Теперь нам нужно сгенерировать ключ.Для нашего примера мы сгенерируем ключ RSA.Это делается с помощью RSA_generate_key
функция, которая объявлена в openssl/rsa.h
.Эта функция возвращает указатель на RSA
структура.
Простой вызов функции может выглядеть следующим образом:
RSA * rsa;
rsa = RSA_generate_key(
2048, /* number of bits for the key - 2048 is a sensible value */
RSA_F4, /* exponent - RSA_F4 is defined as 0x10001L */
NULL, /* callback - can be NULL if we aren't displaying progress */
NULL /* callback argument - not needed in this case */
);
Если возвращаемое значение RSA_generate_key
является NULL
, а потом что-то пошло не так.Если нет, то теперь у нас есть ключ RSA, и мы можем назначить его нашему EVP_PKEY
структура из более ранних:
EVP_PKEY_assign_RSA(pkey, rsa);
Тот Самый RSA
структура будет автоматически освобождена, когда EVP_PKEY
структура освобождается.
Теперь перейдем к самому сертификату.
OpenSSL использует X509
структура для представления сертификата x509 в памяти.Определение для этой структуры находится в openssl/x509.h
.Первая функция, которая нам понадобится, это X509_new
.Его использование относительно просто:
X509 * x509;
x509 = X509_new();
Как это было в случае с EVP_PKEY
, существует соответствующая функция для освобождения структуры - X509_free
.
Теперь нам нужно задать несколько свойств сертификата, используя некоторые X509_*
функции:
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
При этом серийный номер нашего сертификата будет равен "1".Некоторые HTTP-серверы с открытым исходным кодом отказываются принимать сертификат с серийным номером "0", который используется по умолчанию.Следующий шаг - указать промежуток времени, в течение которого сертификат действительно действителен.Мы делаем это с помощью следующих двух вызовов функций:
X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
В первой строке задается размер сертификата notBefore
свойство для текущего времени.(Тот самый X509_gmtime_adj
функция добавляет указанное количество секунд к текущему времени - в данном случае нет.) Во второй строке задается срок действия сертификата. notAfter
свойство действует через 365 дней (60 секунд * 60 минут * 24 часа * 365 дней).
Теперь нам нужно установить открытый ключ для нашего сертификата, используя ключ, который мы сгенерировали ранее:
X509_set_pubkey(x509, pkey);
Поскольку это самозаверяющий сертификат, мы заменяем имя эмитента именем субъекта.Первым шагом в этом процессе является получение названия объекта:
X509_NAME * name;
name = X509_get_subject_name(x509);
Если вы когда-либо раньше создавали самозаверяющий сертификат в командной строке, вы, вероятно, помните, что вас просили ввести код страны.Вот где мы предоставляем его вместе с организацией ('O') и общим названием ('CN').:
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
(unsigned char *)"CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
(unsigned char *)"MyCompany Inc.", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
(unsigned char *)"localhost", -1, -1, 0);
(Я использую здесь значение "CA", потому что я канадец, и это код нашей страны.Также обратите внимание, что параметр # 4 должен быть явно приведен к unsigned char *
.)
Теперь мы действительно можем установить имя эмитента:
X509_set_issuer_name(x509, name);
И, наконец, мы готовы приступить к процессу подписания.Мы называем X509_sign
с помощью ключа, который мы сгенерировали ранее.Код для этого до боли прост:
X509_sign(x509, pkey, EVP_sha1());
Обратите внимание, что мы используем SHA-1 алгоритм хеширования для подписи ключа.Это отличается от mkcert.c
демо, о котором я упоминал в начале этого ответа, в котором используется MD5.
Теперь у нас есть самозаверяющий сертификат!Но мы еще не закончили - нам нужно записать эти файлы на диск.К счастью, OpenSSL и там снабдил нас информацией о PEM_*
функции, которые объявлены в openssl/pem.h
.Первое, что нам понадобится, это PEM_write_PrivateKey
за сохранение нашего секретного ключа.
FILE * f;
f = fopen("key.pem", "wb");
PEM_write_PrivateKey(
f, /* write the key to the file we've opened */
pkey, /* our key from earlier */
EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */
"replace_me", /* passphrase required for decrypting the key on disk */
10, /* length of the passphrase string */
NULL, /* callback for requesting a password */
NULL /* data to pass to the callback */
);
Если вы не хотите шифровать закрытый ключ, то просто передайте NULL
для третьего и четвертого приведенных выше параметров.В любом случае, вы определенно захотите убедиться, что файл недоступен для чтения во всем мире.(Для пользователей Unix это означает chmod 600 key.pem
.)
Ух ты!Теперь мы перешли к одной функции - нам нужно записать сертификат на диск.Функция, которая нам нужна для этого, такова PEM_write_X509
:
FILE * f;
f = fopen("cert.pem", "wb");
PEM_write_X509(
f, /* write the certificate to the file we've opened */
x509 /* our certificate */
);
И мы закончили!Надеюсь, информации в этом ответе достаточно, чтобы дать вам приблизительное представление о том, как все работает, хотя мы едва коснулись поверхности OpenSSL.
Для тех, кому интересно посмотреть, как весь приведенный выше код выглядит в реальном приложении, я собрал воедино суть (написанную на C ++), которую вы можете просмотреть здесь.
Есть ли шанс сделать это через system
звонить из вашего приложения?Несколько веских причин для этого:
Лицензирование:Вызывая
openssl
исполняемый файл, возможно, отделяет его от вашего приложения и может предоставить определенные преимущества. Отказ от ответственности:проконсультируйтесь по этому поводу с юристом.Документация:OpenSSL поставляется с феноменальный документация командной строки, которая значительно упрощает потенциально сложный инструмент.
Тестируемость:вы можете использовать OpenSSL из командной строки, пока не поймете точно, как создавать свои сертификаты.Есть целый ряд лот из вариантов;рассчитывайте потратить на это около дня, пока не разберетесь во всех деталях.После этого нетрудно включить команду в ваше приложение.
Если вы решите использовать API, проверьте openssl-dev
список разработчиков на www.openssl.org.
Удачи вам!
Очень простое руководство по созданию цифровых сертификатов http://publib.boulder.ibm.com/infocenter/rsthelp/v8r0m0/index.jsp?topic=/com.ibm.rational.test.lt.doc /topics/tcreatecertopenssl.html р>
В выполнении этих команд из вашего кода я не уверен.