19.06.2007 6:38:46подчиненный ЦС Ответов: 2
Денис
Здравствуйте!
Возникла необходимость создать подчиненный ЦС. Но при установке ЦС Microsoft не получается использовать сертификат подчиненного ЦС, подписанный корневым ЦС.
При установке ЦС Microsoft выбираем тип ЦС = «Изолированный подчиненый ЦС».
Ставим галку в «Измененные параметры создания пары ключей и сертификата ЦС».
При выборе криптопровайдера «CryptoPro-GOST R 34.10-2001» становится доступным поле выбора ключевого контейнера, но сертификат соответствующий этому ключу недоступен.

При связке ключа и сертификата непонятно какой тип хранилища для сертификата нужно выбирать. Ведь ключ то «машинный»! Может нужно как то в запросе прописать связь сертификата с ключом?

Среда: Windows 2003 Server + CryptoPro CSP 3.0 (CSP +TLS).

Генерим ключевой контейнер. В принципе с ключем проблем нет, но на всякий случай привожу код (Borland C++ Builder 6.0):
// ------------------------------------------------------
int rv = 0;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
CHAR szUserName[100];
DWORD dwUserNameLen = 100;
LPCSTR UserName= “SubCA”;

// Инициализируем криптопровайдера
rv = CryptAcquireContext(
&hCryptProv,
UserName,
NULL,
75,
CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET);

// Получаем контекст криптопровайдера
rv = CryptGetProvParam(
hCryptProv,
PP_CONTAINER,
(BYTE *)szUserName,
&dwUserNameLen,
0);

// Генерим ключ
rv = CryptGenKey(
hCryptProv,
AT_SIGNATURE,
CRYPT_EXPORTABLE,
&hKey);

// ОСвобождение
CryptReleaseContext(hCryptProv,0);
// ------------------------------------------------------

Создается ключевой контейнер, через панель управления КриптоПро видимый как «машинный» ключ.

Далее создаем запрос:

// ------------------------------------------------------

CERT_REQUEST_INFO certReqInfo;
PCERT_REQUEST_INFO pRequestInfo;
pRequestInfo = &certReqInfo;
CERT_NAME_BLOB subjNameBlob;
DWORD encNameLen;
PBYTE encName;
HCRYPTPROV hCryptProv;
DWORD pubKeyInfoLen;
PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL;
DWORD encCertReqLen;
CRYPT_OBJID_BLOB params;
CRYPT_ALGORITHM_IDENTIFIER sigAlg;
PBYTE signedEncCertReq;
DWORD size=0;
DWORD encType= PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;

… Кодирование субъекта опускаю….

// Расширения
PCERT_EXTENSION pExt;
CERT_EXTENSION Exts[4];
CERT_EXTENSIONS ReqExts;
memset(Exts, 0, sizeof(CERT_EXTENSION));
ReqExts.cExtension = 0;
ReqExts.rgExtension = Exts;

// Указываем что это сертификат ЦС (CA:TRUE)
Exts[0].pszObjId = szOID_BASIC_CONSTRAINTS2;
Exts[0].fCritical = 1;
CERT_BASIC_CONSTRAINTS2_INFO BasicConstrains;
BasicConstrains.fCA = 1;
BasicConstrains.fPathLenConstraint = 0;
BasicConstrains.dwPathLenConstraint = 0;

rv = CryptEncodeObjectEx(encType, szOID_BASIC_CONSTRAINTS2, &BasicConstrains,
CRYPT_ENCODE_ALLOC_FLAG, NULL, &Exts[0].Value.pbData,
&Exts[0].Value.cbData);
ReqExts.cExtension++;

// Использование ключа
Exts[1].pszObjId = szOID_KEY_USAGE;
Exts[1].fCritical = 0;

CRYPT_BIT_BLOB KeyUses;
BYTE byte[1];
byte[0] = CERT_DIGITAL_SIGNATURE_KEY_USAGE|
CERT_KEY_CERT_SIGN_KEY_USAGE| CERT_OFFLINE_CRL_SIGN_KEY_USAGE |
CERT_CRL_SIGN_KEY_USAGE;

KeyUses.pbData=byte;
KeyUses.cbData=1;
KeyUses.cUnusedBits=0;

rv = CryptEncodeObjectEx(encType, szOID_KEY_USAGE, &KeyUses,
CRYPT_ENCODE_ALLOC_FLAG, NULL, &Exts[1].Value.pbData,
&Exts[1].Value.cbData);
ReqExts.cExtension++;

// Версия ЦС (v0.0)
Exts[2].pszObjId = szOID_CERTSRV_CA_VERSION;
Exts[2].fCritical = 0;

BYTE Data[] = {0x02, 0x01, 0x00};
Exts[2].Value.cbData = 3;
Exts[2].Value.pbData = Data;
ReqExts.cExtension++;

// Имя шаблона сертификата (SubCA)
Exts[3].pszObjId = szOID_ENROLL_CERTTYPE_EXTENSION;
Exts[3].fCritical = 0;
BYTE DataS[] = {0x1e, '\n', 0x00, 'S', 0x00, 'u', 0x00, 'b', 0x00, 'C', 0x00, 'A'};
Exts[3].Value.cbData = 12;
Exts[3].Value.pbData = DataS;
ReqExts.cExtension++;

// Добавление расширений в сертификат
pRequestInfo->cAttribute = 1;
pRequestInfo->rgAttribute = (PCRYPT_ATTRIBUTE)malloc(sizeof(CRYPT_ATTRIBUTE));
pRequestInfo->rgAttribute[0].pszObjId = szOID_CERT_EXTENSIONS;
pRequestInfo->rgAttribute[0].cValue = 1;
pRequestInfo->rgAttribute[0].rgValue = (PCRYPT_ATTR_BLOB)malloc(sizeof(CRYPT_ATTR_BLOB));

rv = CryptEncodeObjectEx(encType, szOID_CERT_EXTENSIONS, &ReqExts,
CRYPT_ENCODE_ALLOC_FLAG, NULL, &pRequestInfo->rgAttribute[0].rgValue[0].pbData,
&pRequestInfo->rgAttribute[0].rgValue[0].cbData);

// Ну и подписание запроса
// Инициализируем криптопровайдера
rv = CryptAcquireContext(
&hCryptProv,
Container,
NULL,
75,
CRYPT_MACHINE_KEYSET);
// Экспорт ключа
rv = CryptExportPublicKeyInfo (hCryptProv, AT_SIGNATURE,
encType, NULL, &pubKeyInfoLen);
pubKeyInfo = (PCERT_PUBLIC_KEY_INFO) malloc (pubKeyInfoLen);
rv = CryptExportPublicKeyInfo (hCryptProv, AT_SIGNATURE,
encType, pubKeyInfo, &pubKeyInfoLen);
certReqInfo.SubjectPublicKeyInfo = *pubKeyInfo;
memset(&params, 0, sizeof(params));
sigAlg.pszObjId = szOID_CP_GOST_R3411_R3410EL;
sigAlg.Parameters = params;
rv = CryptSignAndEncodeCertificate (hCryptProv, AT_SIGNATURE,
encType,
X509_CERT_REQUEST_TO_BE_SIGNED, &certReqInfo,
&sigAlg, NULL, NULL,
&encCertReqLen);
signedEncCertReq = (PBYTE)malloc(encCertReqLen);
rv = CryptSignAndEncodeCertificate (hCryptProv, AT_SIGNATURE,//AT_KEYEXCHANGE,
encType,
X509_CERT_REQUEST_TO_BE_SIGNED, &certReqInfo,
&sigAlg, NULL, signedEncCertReq,
&encCertReqLen);

ofstream outfile(“req.p10”, ios::binary);
outfile.write(signedEncCertReq, encCertReqLen);
outfile.close();
// ------------------------------------------------------

Отправляем запрос в корневой ЦС (тоже Windows 2003 Server + CryptoPro CSP 3.0 (CSP +TLS)). Сертификат подписывается – все ОК!!!

Вот тут начинается засада…
При привязке сертификата к ключу используем панель управления КриптоПро. При установке личного сертификата выбираем контейнер машинного ключа “SubCA”, далее следует выбрать тип хранилища – выбираем «ЛИЧНОЕ» (А КАКОЕ НУЖНО?).
Для верности устанавливаем сертификат в контейнер закрытого ключа. При просмотре через панель управления КриптоПро сертификат действительно находится в контейнере!

Но при установке ЦС ключ доступен, а сертификат нет!!! Может в сертификате что-то не так? Или при связке сертификата и ключа???
 
Ответы:
19.06.2007 11:34:10Василий
> При привязке сертификата к ключу используем панель управления КриптоПро. При установке личного сертификата выбираем контейнер машинного ключа “SubCA”, далее следует выбрать тип хранилища – выбираем «ЛИЧНОЕ» (А КАКОЕ НУЖНО?).

Тут зависит от деталей.
Правильный алгоритм:
Панель CSP - Сервис - Установить личный сертификат - указываете файл сертификата, затем перед Обзором контейнеров переставляете галку на контейнеры компьютера, потом выбираете контейнер и далее имя хранилища - Личные.

Кроме того, сертификат корневого ЦС должен быть установлен в "Доверенные корневые ЦС" ЛОКАЛЬНОГО КОМПЬЮТЕРА, а сертификат подчинённого ЦС - в "Промежуточные ЦС" ЛОКАЛЬНОГО КОМПЬЮТЕРА.
Список отозванных сертификатов корневого ЦС должен быть установлен в "Доверенные корневые ЦС" ЛОКАЛЬНОГО КОМПЬЮТЕРА.


> Для верности устанавливаем сертификат в контейнер закрытого ключа. При просмотре через панель управления КриптоПро сертификат действительно находится в контейнере

Не имеет значения - сертификат берётся из хранилища, а не из контейнера.

> Но при установке ЦС ключ доступен, а сертификат нет!!! Может в сертификате что-то не так? Или при связке сертификата и ключа???

Если сделано всё вышеперечисленное, то дополнительно рекомендуется поменять пароль на контейнер “SubCA” на пустой на время установки MS CA. Потом можно будет поставить.
19.06.2007 12:45:32Денис
Василий, большое спасибо! Всё заработало!
Тема закрыта.