Программно создайте сертификат X509 с помощью OpenSSL

StackOverflow https://stackoverflow.com/questions/256405

Вопрос

У меня есть приложение на 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

В выполнении этих команд из вашего кода я не уверен.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top