| ||||
| ||||
1 В каком хранилище Windows 2000 server CA хранит CRL? 2 Почему из файла gost_ca.crl не создается контекст CRL? Ф-я CertCreateCRLContext говорит ASN1Error. Хотя ASN1 разборщик говорит что 0 ошибок. 3 Есть какой-нибудь пример для работы с LDAP применительно к CRL? (я исходники имею ввиду) | ||||
Ответы: | ||||
| ||||
мне тоже интересен этот вопрос. а именно - программный разбор CRL. в sample я не нашел примера работы с CRL. спасибо. | ||||
| ||||
1. Локальный компьютер - Промежуточные центры сертификации (HKLM/CA) 2. CRL не в base64 случайно? Работа с CRL_CONTEXT вообщем-то полностью аналогична работе с CERT_CONTEXT, а какого рода разбор интересует? | ||||
| ||||
c CERT_CONTEXT получаю сначала контекст: ... store:= CertOpenSystemStore(hprov, ’MY’); cert:= CertEnumCertificatesInStore(store, nil); ... и нормально работаю дальше со структурой с CRL_CONTEXT не могу получить контекст структуры: flags:=CERT_STORE_SIGNATURE_FLAG or CERT_STORE_TIME_VALIDITY_FLAG; CertGetCRLFromStore(store,cert,nil,@flags) функция CertGetCRLFromStore не отрабатывает. | ||||
| ||||
А что значит не отрабатывает? GetLastError возвращает что-нибудь? | ||||
| ||||
(чего там было то год назад....) Как сейчас помню- пытался я научиться работать с CRL с целью поиска там заданного сертификата (писал я функцию bool IsCertificateValid(...)) Порылся по хранлищам W2kserver - не нашел CRL. ok, экспортировал его из W2kserver’s CA, и пытался создать контекст CRL. Не вышло. ... Закоментировал эту проверку и дальше писал :) Нет, не было там Base64 - мой ASN1 разборщик такое бы просто не сожрал. DER там была. | ||||
| ||||
Тогда сложно сказать ))) Но CertCreateCRLContext создает CRL_CONTEXT из DER без проблем, дело скорее всего было в чем-то другом. | ||||
| ||||
GetLastError возвращает 2148081668 | ||||
| ||||
это CRYPT_E_NOT_FOUND значит, CRL изданный этим центром отсутствует в хранилище либо он просрочен | ||||
| ||||
мм-да, вроде и не просрочен и во все хранилища для верности запихал, может это поэтому что я взял CRL с Вашего тестового центра, а не использую какой-то другой | ||||
| ||||
А CertEnumCRLsInStore его находит? | ||||
| ||||
да вроде отрабатывает ... crlcnt:= CertEnumCRLsInStore(store,nil); if crlcnt = nil then ShowMessage(’NO - ’+IntToStr(GetLastError)) else ShowMessage(’CertEnumCRLsInStore - YES’); ... | ||||
| ||||
значит, если CRL свежий, проблема в сертификате издателя. Возможно, для CertGetCRLFromStore вы передаете не тот сертификат. | ||||
| ||||
Еще несколько вопросов: 1. Надо ли полученную структуру PCCRL_CONTEXT чтобы получить из неё серийные номера и даты отзыва сертификатов? 2. Где конкретно в этой структуре лежат серийные номера и даты отзыва сертификатов? 3. Сколько в принципе может существовать в хранилище списков CRL одного издателя - 1 или больше, и разных издателей? | ||||
| ||||
1. Да, надо. 2. Даты и серийные номера лежат в CRL_CONTEXT::CRL_INFO, в массиве rgCRLEntry. 3. Возможно и то и другое | ||||
| ||||
:)) В первом вопросе имелось ввиду надо ли декодировать структуру? | ||||
| ||||
В каком смысле декодировать? У Вас есть blob СRL в DER, Вы его подсовываете CertCreateCRLContext и все. | ||||
| ||||
Окончательно запутался: 1.Зачем выполнять CertCreateCRLContext, которая возвращает PCCRL_CONTEXT, усли у меня уже есть PCCRL_CONTEXT после чтения из файла 2.Получаю из PCCRL_CONTEXT даты начала действия и след. обновления: FileTimeToSystemTime(Pinfo^.pCrlInfo^.ThisUpdate,thisupd); FileTimeToSystemTime(Pinfo^.pCrlInfo^.NextUpdate,nextupd); ShowMessage(’CRL - действителен c : ’+DateTimeToStr(SystemTimeToDateTime(thisupd))+#10#13+ ’CRL - следующее обновление : ’+DateTimeToStr(SystemTimeToDateTime(nextupd))); С этим нормально, получаю дату отзыва первого сертификата: FileTimeToSystemTime(Pinfo^.pCrlInfo^.rgCRLEntry^.RevocationDate,revdate); ShowMessage(’CRL - дата отзыва : ’+DateTimeToStr(SystemTimeToDateTime(revdate))); Не могу получить даты и серийные номера остальных сертификатов, подскажите как их вытащить? | ||||
| ||||
1. Не понял, а из файла как CRL_CONTEXT получается. 2. Суть в том, что CRL_INFO::rgCRLEntry - это массив отозванных сертифкатов в это CRL, CRL_INFO::cCRLEntry - количество элементов в нем. Но как перебрать элементы в массиве на Паскале, я не подскажу :) не помню уже. | ||||
| ||||
CRL_CONTEXT получаю из файла, переделав Вашу функцию read_cert_from_file из примеров Спасибо. | ||||
| ||||
А то, что вместо серийных номеров отозванных сертификатов в формате ’xxxx xxxx xxxx xxxx xxxx’ я получаю 3 для 1-го отозваноого из списка, 5 - для второго и т.д. - 6,7,8,9,11,12. Это нормально, или нет??? | ||||
| ||||
Нет, не нормально. Серийные номера хранятся в формате CRYPTOAPI_BLOB, как Вы его преобразовываете? | ||||
| ||||
Я пытаюсь получить его из структуры Pinfo.pCrlInfo.rgCRLEntry.SerialNumber, где Pinfo.pCrlInfo.rgCRLEntry.SerialNumber.cbdata - размер в байтах, Pinfo.pCrlInfo.rgCRLEntry.SerialNumber.pbData - указатель на данные, я правильно понимаю или нет, наставьте на путь истинный, please! | ||||
| ||||
все правильно, именно отсюда и берется | ||||
| ||||
а номера там в 16-ричном виде лежат, как отображаются, или в каком-то другом? | ||||
| ||||
да, в 16ричном. в каждом байте лежат по две цифры серийного номера | ||||
| ||||
Спасибо, с серийниками разобрался, подскажите c причиной отзыва. Лежит в Pinfo.pCrlInfo.rgCRLEntry.rgExtension.Value ? И что лежит в Pinfo.pCrlInfo.rgCRLEntry.rgExtension.fCritical и Pinfo.pCrlInfo.rgCRLEntry.rgExtension.pszObjId ? | ||||
| ||||
причина отзыва лежит Value расширения с OID 2.5.29.21. fCritical - это признак того, является ли это расширение критическим или нет. Причина отзыва критическим расширением не является. | ||||
| ||||
У меня все Pinfo.pCrlInfo.rgCRLEntry.rgExtension.pszObjId возвращают 2.5.29.21, хотя визуально я вижу, что причины отзыва разные. | ||||
| ||||
Конечно :) OID определяет, что в этом расширении содержится причина отзыва, а поле Value собственно уже содержит значение этой причины | ||||
| ||||
Подскажите в каком виде хранится причина отзыва, надо ли ей делать CertOIDToAlgId(), хотя наверно нет, не надо случайно ничего там декодировать? | ||||
| ||||
ничего не надо делать, код хранится в открытом виде. CRLReason ::= ENUMERATED { unspecified (0), keyCompromise (1), cACompromise (2), affiliationChanged (3), superseded (4), cessationOfOperation (5), certificateHold (6), removeFromCRL (8) } (из RFC 2459) | ||||
| ||||
Да, спасибо, почему спрашивал на счет декодирования, у меня вместо 0,1..8 возвращается 0110, 1110, 2110, 3110..8110 Можно конечно использовать только первый символ только некрасиво получается | ||||
| ||||
упс, это я наврал, прошу прощения. надо конечно же сделать CryptDecodeObject с параметром szOID_CRL_REASON_CODE | ||||
| ||||
Не понимаю, я правильно делаю или нет: CryptDecodeObject(encType,szOID_CRL_REASON_CODE,pbEncoded,cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,nil,@pcbStructInfo); GetMem(pvStructInfo,pcbStructInfo); CryptDecodeObject(encType,szOID_CRL_REASON_CODE,pbEncoded,cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,nil,@pcbStructInfo) | ||||
| ||||
А почему оба вызова CryptDecodeObject одинаковые? Во втором вместо nil должно быть pvStructInfo | ||||
| ||||
Получаю даты из сертификата или из CRL, даты получаются нормально, но на 4 часа меньше, чем при просмотре самого сертификата или CRL, разницап между Москвой и Гринвичем или что? что делать - добавлять везде по 4 часа? | ||||
| ||||
Да. Из MSDN: "Time is UTC-time encoded as a eight-byte date/time precise to seconds with a two digit year (that is, YYMMDDHHMMSS plus 2 bytes)." 4 часа конечно можно прибавлять, но это не очень хороший выход, лучше воспользоваться функцией FileTimeToLocalFileTime. | ||||