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


У меня есть приложение C/C++, и мне нужно создать сертификат PEM X509, содержащий как открытый, так и закрытый ключ. Сертификат может быть самоподписанным, или нет, не важно.

Я хочу сделать это внутри приложения, а не из командной строки.

какие функции OpenSSL сделают это для меня? Любой пример кода-это бонус!

4 60

4 ответа:

сначала вам нужно ознакомиться с терминологией и механизмами.

Сертификат X. 509 сертификат по определению, не содержит закрытого ключа. Вместо этого это подписанная CA версия открытого ключа (вместе с любыми атрибутами, которые CA помещает в подпись). Формат PEM действительно поддерживает только отдельное хранение ключа и сертификата - хотя вы можете затем объединить их.

в любом случае, вам нужно будет вызвать 20+ различные функции API OpenSSL для создания ключа и самозаверяющего сертификата. Пример находится в самом источнике OpenSSL, в demos/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);

The 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.

для тех, кто заинтересован в том, чтобы увидеть, как выглядит весь приведенный выше код в реальном приложении, я собрал Gist (написанный на 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

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