18.04.2005 12:46:55Научите обновлять сертификат Ответов: 19
SeregaEvg
Есть пользователь, который имеет свой установленный сертификат и в данный момент по нему работает. Но сертификат пользователя скоро истечет.

Надо обновить сертификат пользователя. Как это сделать грамотно?

Пока мысли такие:
Взять строку запроса из старого сертификата пользователя.

Сгенерить новую пару ключей.

Создать на этой основе запрос.

Подписать запрос старым (но еще действующим) ключом пользователя.

Пока я не полностью представляю себе задачу, в связи с этим, вопрос: правильно ли я мыслю или не особо? Может, есть более правильный способ "обновления"?
 
Ответы:
18.04.2005 14:47:43Василий
Процедура обновления ключей должна быть описана в Регламенте услуг Удостоверяющего центра, выдающего сертификаты. Возможные варианты:
1) бумажное заявление от пользователя
2) подписанный старым ключом запрос на новый сертификат
варианты доставки этих документов - личная явка, почта, эл. почта, АРМ пользователя - опять-же, определяются Регламентом.
18.04.2005 15:27:37SeregaEvg
У меня вопрос точки зрения программиста. Пока порядок "бумажного" оформления я в расчет не беру: конечно будет бумага и файл запроса на сертификат.

Вот этот файл-то мне и надо подготовить. Есть два момента: оставить клиенту ту же самую пару ключей (не хотелось бы), либо создать новую пару, но сделать не самоподписанный запрос, а запрос, подписанный старой подписью клиента. Интересно, такой запрос может быть обработан на стороне ЦС или нет?
18.04.2005 15:38:25Василий
Работает же...
В "КриптоПро УЦ" (http://www.cryptopro.ru/CryptoPro/products/uc.asp) применяется именно такая схема - запрос на новый сертификат pkcs10 (соответствующий новому открытому ключу) подписывается пользователем на старом (но ещё действующем) ключе и отправляется на обработку на Центр регистрации в виде pkcs7. Это в случае плановой смены ключей при распределённой схеме обслуживания. Далее, после проверки подписи и принятия решения, на ЦС передается pkcs10, полученный из pkcs7.
11.07.2005 12:04:35SeregaEvg
А в PKCS7 куда запихнуть запрос? Какую структуру надо заполнить и как закодировать, чтобы получился "перезапрос" в виде PKCS7?

(у нас пока используется майкрософтовский центр сертификации, может, аналогично)

Понимаю, что это немного оффтопик, но у вас лучший русскоязычный криптофорум, который я знаю.
11.07.2005 15:00:10Kirill Sobolev
1. PKCS10 подписываете как DER, получаете PKCS7
2. На ЦС проверяете подпись, вытаскиваете из PKCS7 PKCS10
3. PKCS10 отдаете ЦС
12.07.2005 14:09:36SeregaEvg
А при подписи что писать в CRYPT_SIGN_MESSAGE_PARA.HashAlgoritm?

Я указываю pszObjId = szOID_CP_GOST_R3411_R3410 (по аналогии с CryptSignAndEncodeCertificate), но, наверное, надо и CRYPT_SIGN_MESSAGE_PARA.HashAlgorithm.Parameters чем-то заполнить... А чем?
12.07.2005 14:18:07Kirill Sobolev
В случае ГОСТа:
pszObjId дб szOID_CP_GOST_R3411 (szOID_CP_GOST_R3411_R3410 это алгоритм подписи а не хэша). Parameters заполнить нулями. В signtsf.c csptest есть пример подписи.
12.07.2005 18:16:53SeregaEvg
Да вроде, за исключением того, что время в атрибуты не добавляю, все так и делаю... Кроме AccessViolation пока ничего добиться не удалось.

Подписываемые данные нормальные, читаются, в файл сохраняются. Может, их закодировать надо предварительно?

Может, есть в чем-то ньюанс?
Длину в структуре заполнил,
сертификат - установленный, существующий, Алгоритм - szOID_CP_GOST_R3411 ("1.2.643.2.2.9"), его параметры - нули.
Остальное - тоже нули.

Откуда ж AV?
13.07.2005 8:49:03SeregaEvg
Не удалось победить этот AccessViolation.

smp: CRYPT_SIGN_MESSAGE_PARA;
arrcb: Array [0..0] of Cardinal;
arrpb: Array [0..0] of PByte;

заполняю так:
ZeroMemory(@smp, SizeOf(CRYPT_SIGN_MESSAGE_PARA));

smp.cbSize:= SizeOf(CRYPT_SIGN_MESSAGE_PARA);
smp.dwMsgEncodingType := X509_ASN_ENCODING or PKCS_7_ASN_ENCODING;
smp.pSigningCert := pcc; // Этот PCCERT_CONTEXT нормальный, по крайней мере поля оттуда "выдираются"

smp.HashAlgorithm.pszObjId:= szOID_CP_GOST_R3411; // сам написал, что szOID_CP_GOST_R3411 = ’1.2.643.2.2.9’
smp.HashAlgorithm.Parameters.cbData := 0;
smp.HashAlgorithm.Parameters.pbData := nil;

smp.pvHashAuxInfo:= nil;

smp.cMsgCert:= 0;
smp.rgpMsgCert:= nil;

smp.cMsgCrl := 0;
smp.rgpMsgCrl := nil;

smp.cAuthAttr:= 0;
smp.rgAuthAttr := nil;

smp.cUnauthAttr:= 0;
smp.rgUnauthAttr:= nil;

smp.dwInnerContentType:= 0;
smp.cMsgCrl:= 0;

smp.dwFlags:= 0;

smp.dwInnerContentType := 0;


arrcb[0] := BlockLength; // DWORD
arrpb[0] := BlockPtr; // Pointer



Вызов:
CryptSignMessage(@smp, DetachedSign, 1, arrpb, arrcb, nil, @dw)
13.07.2005 21:46:42SeregaEvg
Вопрос: CryptSignMessage подписывает произвольный BLOB или его надо предварительно как-нибудь закодировать? (Вроде, произвольный должен быть)

Есть какие-нибудь условия на сертификат? Как определить, что сертификатом можно подписывать? Но если нелья было бы, то тогда ошибка через GetLastError возвращалась бы, а не AV вылетало...
14.07.2005 10:03:58Kirill Sobolev
Да, BLOB произвольный.
Если бы сертификат не подходил (нет секретного ключа, неправильное назначение ключа), то ошибка возвращается в GetLastError конечно.
14.07.2005 17:45:00SeregaEvg
в signtsf интересное место есть:
hCertStohCertStore = CertOpenStore(re = CertOpenSystemStore(0,"MY")) закомментировано

и написано

hCertStore = CertOpenStore(...

У меня контекст сертификата получается как раз через CertOpenSystemStore(0,"MY")) - неужели это критично?

Причем алгоритм такой: Открываем хранилище, формируем список сертификатов(формируя из них массив CERT_CONTEXT), зкарываем хранилище. Возвращаем на выходе выбранный элемент из массива CERT_CONTEXT. Остается ли он валидным после закрытия хранилища?



14.07.2005 17:51:39Kirill Sobolev
Нет, если сертификат в личных, то некритично.
Нет, не остается.
MSDN: To force the freeing of memory for all contexts associated with a store, set CERT_STORE_CLOSE_FORCE_FLAG. With this flag set, memory for all contexts associated with the store is freed and all pointers to certificate, CRL, or CTL contexts associated with the store become invalid. This flag should only be set when the store is opened in a function and neither the store handle nor any of its contexts were ever passed to any called functions.
14.07.2005 17:58:08SeregaEvg
Я не упомянул, но я делаю CertDuplicateCertificateContext и сохраняю именно CERT_CONTEXT а не PCCERT_CONTEXT (хотя там все равно структура, содержащая указатели...)

То есть нельзя делать CertCloseStore до CryptSignMessage?
14.07.2005 18:46:53SeregaEvg
Чего-то у меня самые простые вопросы, но ответов сформулировать не могу:

1)
Вот в signnsf:

Поолучение PCCERT_CONTEXT:
pUserCert = read_cert_from_my(certfile)

read_cert_from_my написана в tmain.c:
CertOpenStore(...)
res = CertFindCertificateInStore(...)
CertCloseStore(...)

То есть после выхода из функции res уже инвалидный?

2)
Что имеется в виду под "char* certfile" в функции do_sign? Имя файла, содержащего сертификат (судя по названию) или Subject искомого сертификата (судя по смыслу)?

Искать первый попавшийся сертификат в хранилище по полю subject - это не очень-то надежно (ведь могут быть два сертификата с одинаковыми: выданные в разное время или разными CA) Я понимаю, что это пример, но все же? Я пришел к тому, что искать надо по совокупности Issuer+SerialNumber.

4)
Обязательно ли добавлять время подписи? (я не добавляю и массив атрибутов у меня пуст)

15.07.2005 9:29:11SeregaEvg
И можно еще один вопрос: есть PCCERT_CONTEXT. Как получить имя контейнера, содержащего закрытый ключ, соответствующий данному сертификату?

(понимаю, что тема многократно обсасывалась, но поиском по сайту найти не могу)
15.07.2005 10:39:24Kirill Sobolev
1. Нет, валидный. Там закрывается с флагом 0. Вообщем, посмотрите описание CertCloseStore
2. Правильно по смыслу :) Название немного неудачное, видимо осталось от времен, когда сертификат задавался файлом.
Про поиск согласен - если СА гарантирует уникальность серийных номеров. Но csptest - это не система защищенного документооборота а всего лишь пример использования функций CryptoAPI :)
3. Необязательно
4. CertGetCertificateContextProperty(,CERT_KEY_PROV_INFO_PROP_ID,,)
15.07.2005 12:01:07SeregaEvg
Я тоже делаю CertCloseStore с флагом 0
MSDN читал именно поэтому и задал вопрос (в общем ладно, понятно - проехали).

Так вот если после закрытия хранилища я использую CertGetCertificateContextProperty - у меня AV.
А вот если в цикле перебора сертификатов - то все ок. Но до того, чтобы это в цикле проверить я только сегодня додумался :-(

1)
А в цикле вызов CertEnumCertificatesInStore, следующий за certGetCertificateContextProperty приводит к ошибке. Это почему?

2) когда вызвать certGetCertificateContextProperty (...CERT_KEY_PROV_INFO_PROP_ID...)возвращается не имя контейнера, а что-то непонятное. Как получить все-таки строку с именем контейнера?
15.07.2005 12:15:01Kirill Sobolev
1.К какой ошибке?
2.Там возвращается указатель на CRYPT_KEY_PROV_INFO, поле LPWSTR pwszContainerName как раз то что нужно.