Ця стаття для тих, хто з тих чи інших причин вирішив
написати власний крипто-провайдер для OC сімейства Windows. Якщо Ви хочете
реалізувати у вашому провайдера нестандартні алгоритми, то вам має бути
зіткнутися з певними труднощами. Труднощі можуть виникнути, наприклад,
при спробах використання вашого крипто-провайдера для перевірки сертифікатів в
MS Internet Explorer. p>
Під нестандартними алгоритмами тут розуміються не
всесвітні DES, RSA, DSA і т. д, а, наприклад, алгоритми сімейства ГОСТ. Річ у
те, що для RSA і подібних алгоритмів всі необхідні ідентифікатори вже
зашиті в систему, а для ГОСТ-ів (чи багатьох інших алгоритмів) треба окремо
подбати про те, щоб система їх "побачила". p>
Для прикладів коду використовується Сі. Всі приклади коду
служать тільки для ілюстрації принципів викладених у статті і не є
повноцінними робочими програмами. p>
Також мається на увазі, що в читача є базові
знання в галузі прикладної криптографії і терміни "відкритий ключ", "ASN.1" і
подібні для нього не є загадкою. p>
Інтеграція провайдера в Windows h2>
Окрім наявності бібліотеки самого провайдера
додатково потрібно: p>
зареєструвати провайдер та крипто-алгоритми в
системі, прописавши певні параметри в реєстрі; p>
створити бібліотеку з функціями конвертації ключів
з форматів криптопровайдер в зовнішні формати і зареєструвати ці функції
у реєстрі; p>
замінити функцію I_CryptGetDefaultCryptProvider в
бібліотеці crypt32.dll p>
Тільки після виконання цих дій провайдер
нормально інтегрується в систему і ви зможете, наприклад, генерувати
сертифікати за допомогою вашого провайдера на основі стандартного компонента ОС
Windows Server - Сertification services або на тестовому УЦ КріптоПро
http://www.cryptopro.ru/certsrv p>
Коректно буде відображатися статус перевірки підпису у
сертифікатів, підписаних вашим "нестандартним" алгоритмом і т.п. p>
Далі докладно розглянемо кожен зі згаданих вище
кроків, припускаючи при цьому що бібліотека з Вашим CSP вже є і коректно
працюють всі функції провайдера. p>
Реєстрація крипто-провайдера та алгоритмів в системі h2>
Коли у вас вже є готова бібліотека з реалізацією
функцій CSP, необхідно зареєструвати її в системі, для того щоб новий
крипто-провайдер став доступний різних додатків. p>
Процес реєстрації самого CSP докладно описаний у MDSN,
і повторювати цю інформацію тут сенсу немає. Усе це докладно описано в [1].
Також тут ми не будемо зупинятися на проблемі підпису нового CSP в
Microsoft і шляхи її обходу. Ця проблема вже багаторазово обговорювалася на
різних форумах, наприклад дивіться [3]. Набагато цікавіше розглянути
реєстрацію криптографічних алгоритмів. Кожен алгоритм має свій унікальний
ASN.1 ідентіфіктор Оbject Identifier - OID. Наприклад, алгоритм підпису
ГОСТ-34.10-2001 має такий OID (представлений у вигляді рядка) --
"1.2.643.2.2.3". Ідентифікатор кожного підтримується вашим CSP алгоритму
слід занести до реєстру. Крім OID у кожного криптографічного алгоритму в Windows
існує ще ідентифікатор у вигляді чотирьох-байтового числа - AlgID, за
якому алгоритми ідентифікуються в провайдера. Цей ідентифікатор заноситися
в CSP і його можна дізнатися перерахувавши алгоритми за допомогою виклику CPGetProvParam.
У КріптоПро, наприклад, для алгоритму хешування ГОСТ-34.11-94 AlgID
використовується значення 0x801e p>
Хай нам необхідно зареєструвати алгоритм підпису
ГОСТ-34.10-2001. Тоді в реєстрі необхідно прописати наступні ідентифікатори:
p>
Аналогічно реєструються і інші алгоритми.
Докладну інформацію про структуру CRYPT_OID_INFO можна знайти в MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/crypt_oid_info.asp
p>
Для того щоб провайдер викликався для перевірки
сертифіката, що підписаний нашим "нестандартним" алгоритмом необхідно ще одне
допоміжні дії. p>
Справа в тому, що Windows визначає який провайдер
використовувати для перевірки по полю ExtraInfo (див. посилання в попередньому абзаці для
опису цього поля) в ключі реєстру соответвующему алгоритму підпису - такий
ключ ми створюємо, викликаючи функцію CryptRegisterOIDInfo. Тому треба вказати
системі наш провайдер в якості провайдера за умовчанням для типу, який
занесений до ExtraInfo алгоритму підпису. p>
Наступний код встановлює провайдер за замовчуванням для
певного типу. p>
# define
YOUR_PROV_NAME "MY_PROV" p>
# define YOUR_PROV_TYPE 75 p>
rc = CryptSetProvider ( p>
YOUR_PROV_NAME, p>
YOUR_PROV_TYPE p>
); p>
Сценарії застосування нашого CSP p>
Розглянемо тут два сценарії застосування CSP. p>
Перший сценарій - перевірка підпису сертифікату. Для
перевірки підпису система завантажує відкритий ключ з сертифікату, яким
підписаний що перевіряється. Потім по OID алгоритму підпису перевіряється сертифіката,
так як описано в попередньому розділі статті, визначається необхідний провайдер.
Щоб перевірити підпис, потрібно імпортувати відкритий ключ в CSP і можна було
б подумати що Windows відразу викликає функцію нашого провайдера CPImportKey.
Але не тут-то було! p>
Другий сценарій - генерація ключової пари і відправка
запиту на сертифікат на Засвідчувальний Центр. Windows завантажує наш CSP,
генерує ключову пару і експортує до себе нагору відкритий ключ викликаючи
функцію CPExportKey. Все добре. Начебто треба взяти і розмістити отриманий
буфер з ключем в PKCS # 10 запит, який потім буде відправлений на УЦ. І тут усі
знову не зовсім так. p>
p>
Малюнок 2 - Запит на сертифікат в УЦ p>
p>
Малюнок 3 - Процес створення сертифіката p>
Виявляється, існують проміжні функції для
експорту/імпорту відкритих ключів, і без їх реалізації нічого доброго з нашим
CSP, у згаданих вище двох сценаріях, не вийти. Біда ще й у тому, що
функції ці недокументовані і знайти інформацію по них вкрай складно. Їх
опису присвячений наступний розділ. p>
Опції конвертування ключів h2>
Архітектура кругообігу відкритих ключів для
"Нестандартних" алгоритмів в Windows представлена на картинці: p>
p>
Малюнок 4 - Імпорт та експорт відкритих ключів до/з CSP p>
Функція A_ConvertPublicKeyInfo - на вході приймає
ключ у форматі ASN.1 DER і повинна перетворити його у формат, який
"Розуміє" функція CSP CPImportKey p>
Функція A_EncodePublicKeyInfoAndParameters на вході
бере ключ в тому форматі, в якому ключ експортує CPExportKey. На
вихід A_EncodePublicKeyInfoAndParameters повинна сформувати ASN.1 DER
структуру з ключем - ту ж саму яка в разі імпорту передається в
A_ConvertPublicKeyInfo - на вхід. Сподіваюся, ви не заплуталися у всіх цих входах
Jі виходах p>
Ось сигнатури і нам інформацію про те параметрів цих
функцій: p>
BOOL WINAPI
A_ConvertPublicKeyInfo ( p>
DWORD dwCertEncodingType,// IN - p>
VOID * EncodedKeyInfo,// IN - буфер з ключем - покажчик p>
// на структуру CERT_PUBLIC_KEY_INFO p>
DWORD dwAlg,
//IN - AlgId ключа p>
DWORD dwFlags,// IN - зазвичай 0 p>
BYTE ** ppStructInfo,// OUT - подвійний покажчик на структуру p>
// в заголовку структури йде спочатку PUBLICKEYSTRUC,
потім DSSPUBKEY, p>
// а потім сам
ключ з параметрами p>
DWORD
* StructLen// OUT - довжина структури p>
); p>
BOOL WINAPI
A_EncodePublicKeyAndParameters ( p>
DWORD dwCertEncodingType,// IN p>
LPCSTR lpszStructType,// IN - OID алгоритму p>
const void * pvStructInfo,// IN - така ж структура як p>
// на виході ConvertPublicKeyInfo p>
DWORD nStructLen,// IN - довжина вхідної структури p>
DWORD dwFlags,// IN - зазвичай 0 p>
DWORD Unk,
/ /? - Невідомо p>
BYTE
** pbPubKey,// OUT - відкритий ключ в
ASN.1 DER p>
DWORD *
pcPubKeyLen,// OUT - довжина відкритого
ключа p>
BYTE ** pbParams,// OUT - параметри відкритого ключа p>
DWORD *
pcParamsLen// OUT - довжина параметрів p>
); p>
Формати ключів залежать від крипто-провайдера та
використовуваних алгоритмів. p>
Функція I_CryptGetDefaultCryptProvider з crypt32.dll p>
З незрозумілої для мене причини Windows часто не
намагається шукати потрібний крипто-провайдер за ідентифікатором алгоритму з яким
потрібно працювати. У таких випадках вона просто викликає недокументовані
функцію I_CryptGetDefaultCryptProvider, і якщо той провайдер, який повернула
ця функція, не вміє працювати з даним алгоритмом, то процес завершується з
помилкою. Так відбувається, наприклад, при розборі в Internet Explorer PKCS # 7
відповіді в сценарії із запитом сертифікату на тестовому УЦ. p>
Необхідно замінити цю функцію таким чином, щоб
при нульовому параметрі algid на вході вона повертала наш провайдер, який вже
на відміну від штатного провайдера легко впоратися з "нестандартними
алгоритмами ". p>
Обговорення способів заміни функцій в системній dll
виходить далеко за рамки цієї статті. Можу лише, як один із способів вирішення,
запропонувати бібліотеку Microsoft Detours:
http://research.microsoft.com/sn/detours p>
Прив'язка закритого ключа до сертифіката h2>
На відміну від відкритого ключа закриті ключі ніколи не
залишають крипто-провайдер і тому коли ви бачите що для даного сертифікату
є закритий ключ (як на малюнку) це означає що в контексті цього
сертифіката існує явна посилання на закритий ключ. p>
p>
Малюнок 5 - Закритий ключ сертифіката p>
Контекст сертифіката це набір додаткових
атрибутів сертифіката, які знаходяться не в тілі сертифіката, а зберігаються
окремо від нього. Одним з таких атрибутів і є посилання на закритий ключ,
яка складається з імені провайдера та імені ключового контейнера. p>
Приклад коду для прив'язки закритого ключа до
сертифікату: p>
PCCERT_CONTEXT
pCert; p>
CRYPT_KEY_PROV_INFO prov_info; p>
... p>
prov_info.cProvParam = 0; p>
prov_info.rgProvParam = 0; p>
prov_info.dwFlags = 0; p>
prov_info.dwKeySpec = AT_SIGNATURE; p>
prov_info.dwProvType = 0; p>
prov_info.pwszContainerName = L "key-kont-name"; p>
prov_info.pwszProvName = L "A-CSP"; p>
CertSetCertificateContextProperty ( p>
pCert, p>
CERT_KEY_PROV_INFO_PROP_ID, p>
0, p>
& prov_info p>
); p>
Успіхів у розробці крипто-провайдера! p>
http://www.realcoding.net/ p>
Форми в HTML документах p>
Деякі WWW browser дозволяють користувачеві, заповнивши
спеціальну форму, повертати отримані значення, виконувати деякі
дії на вашому WWW - сервер. Коли форма інтерпретується WEB - оглядачем,
створюється спеціальні екранні елементи GUI, такі, як перемикачі, checkboxes,
radiobuttons, що випадають меню, скролліруемие списки, кнопки і т.д. Коли
користувач заповнює форму і натискає кнопку "Підтвердження"
(SUBMIT - спеціальний тип кнопки, який задається при описі документа);
інформація, введена користувачем у форму, надсилається HTTP-сервером для
обробки та передачі іншим програмам, що працюють під сервером, відповідно
з CGI (Common Gateway Interface) інтерфейсом. p>
Коли ви описуєте форму, кожен елемент введення даних
має тег . Коли користувач поміщає дані в елемент форми,
інфоромація розміщується в розділі VALUE даного елементу. p>