Получение цепочки сертификатов в приватный корень - PullRequest
3 голосов
/ 26 сентября 2011

Я пытаюсь проверить, что сертификат из подписи цепочки обратно к определенному корневому сертификату, который не доверен Windows (это частный сертификат для приложения).

Моя текущая попытка сделать это включает создание механизма цепочки, который доверяет только определенному сертификату, который я хочу получить в качестве корневого, так что никакие другие цепочки не могут быть сгенерированы.

HCERTSTORE hPrivateRootStore = CertOpenStore(CERT_STORE_PROV_FILENAME, dwEncoding,
    NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
    _T("C:\\Test\\PrivateRoot.cer"));
CERT_CHAIN_ENGINE_CONFIG config;
memset(&config, 0, sizeof(config));
config.cbSize = sizeof(config);
config.hRestrictedTrust = hPrivateRootStore;
config.dwFlags = CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL | CERT_CHAIN_ENABLE_SHARE_STORE;
HCERTCHAINENGINE hEngine;
CertCreateCertificateChainEngine(&config, &hEngine);
CERT_CHAIN_PARA params;
memset(&params, 0, sizeof(params));
params.cbSize = sizeof(params);
PCCERT_CHAIN_CONTEXT chains = NULL;
if (CertGetCertificateChain(hEngine, pCertContext, NULL, hStore, &params,
    0, NULL, &chains))
   ...

(проверка ошибок для ясности опущена; pCertContext и hStore получены из CryptQueryObject извлечения подписи и связанных сертификатов из подписанного двоичного файла.)

К сожалению, это не похоже на работу; несмотря на использование собственного механизма цепочки, он все еще ищет в хранилище ОС и либо не находит цепочку, либо находит ее в другом корне (которому доверяет ОС). Я могу получить цепочку, которую только хочу, добавив свой личный корневой сертификат в доверенное хранилище ОС.

Я также пытался установить config.hRestrictedOther в пустое хранилище памяти, поскольку в документах предполагается, что наличие hRestrictedTrust не-NULL снова приведет к системным хранилищам, но это не имеет никакого значения.

Я что-то упускаю или есть лучший способ сделать это?

Редактировать : просто чтобы дать немного больше контекста, я пытаюсь сделать что-то похожее на сертификаты подписи драйверов, где сертификат подписи цепочки обратно к двум различным корням: один стандартный корень CA, которому доверяют ОС и один внутренний корень (которому в драйверах также доверяет ОС, но в моем случае будет доверять только мое приложение). Крест происходит где-то посередине «главной» цепи; потенциально может быть несколько разных файлов, подписанных разными «настоящими» центрами сертификации, но при этом они будут связаны с моим внутренним сертификатом.

1 Ответ

2 голосов
/ 27 сентября 2011

Я нашел полуобработанный обходной путь сейчас;это немного уродливо, но это действительно работает.Я получил основную идею из набора тестов Chromium ;он включает в себя установку хука в Crypt32 таким образом, чтобы при попытке открыть системные хранилища для построения цепочки он получал мое собственное хранилище, содержащее только мой требуемый сертификат.

Хорошо, чтопохоже, это заставляет CertGetCertificateChain проходить «мимо» реального сертификата CA и связывать его с моим пользовательским сертификатом, а не останавливаться на сертификате CA (что обычно и происходит, когда ему доверяют).

Плохо то, что он не мешает строить цепочки и доверять любым другим сертификатам CA.Я могу обойти это, явно проверив, что корень цепочки - это сертификат, который я хотел, но он менее чем идеален, и я не уверен, что есть ситуации, которые могут его отключить.

Все еще в поисках лучших решений;У меня определенно складывается впечатление, что я иду по неверному пути.

Хорошо, новый план.Сейчас я просто иду по цепочке вручную (так как я знаю, что все сертификаты, которые меня интересуют, будут в hStore, извлеченном из подписанного .exe), с базовой структурой, подобной этой:

  • Используйте WinVerifyTrust, чтобы выполнить базовую проверку подлинности "не взломано".
  • Используйте CryptQueryObject, чтобы получить хранилище сертификатов hStore из .exe
  • Используйте CryptMsgGetParam и CertFindCertificateInStore найти сертификат подписи от hStore.
  • Начиная с сертификата подписи, используйте CertFindCertificateInStore с CERT_FIND_SUBJECT_NAME в цикле для поиска сертификатов потенциального эмитента;продолжайте идти до тех пор, пока я не нажму самозаверяющий сертификат или не найду нужный корень (проверка на совпадение с помощью CertComparePublicKeyInfo).
  • Откажитесь от определенной ветви, если CertVerifySubjectCertificateContext говорит, что подписи не совпадают.

Кажется чище, чем предыдущие подходы, которые я пробовал.Мысли / комментарии / альтернативы?

(Что-то, что в некоторых отношениях кажется более целесообразным, это добавить дополнительную пользовательскую контрсигнатуру [похожую на временную метку] вместо того, чтобы пытаться связать сертификаты подобным образом, но я могуне найдете никакой информации о том, как это сделать, или каковы плюсы / минусы.)

...