Я понимаю, что это очень поздний (и длинный) ответ. Но, учитывая, насколько этот вопрос, похоже, занимает место в результатах поисковой системы, я подумал, что, возможно, стоит написать достойный ответ.
Многое из того, что вы будете читать ниже, заимствовано у this demo и документов 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
.)
Whew! Теперь мы ограничимся одной функцией - нам нужно записать сертификат на диск. Функция нам нужно для этого 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++), который вы можете просмотреть here.
OpenSSL не находится под лицензией GPL http://www.openssl.org/source/license.html – Zoredache 2008-11-02 02:55:38
OpenSSL является лицензией по лицензии типа apache, ее можно использовать в коммерческих приложениях, как и любая другая лицензия, отличная от копилефта ,Люди все еще могут обратиться к адвокату, чтобы убедиться, что все, что они делают, в порядке, но у него нет связанных с GPL вопросов. – 2008-11-02 02:58:38
Отмечено и обновлено - спасибо. Разделение открытого кода из кода с закрытым кодом, как правило, является хорошей идеей, и если эффективность не имеет решающего значения, другие причины делают хороший пример для использования автономной утилиты openssl. – 2008-11-02 03:05:31