Библиотека xmlsec - получить тему ключа подписи

Я использую библиотеку xmlsec для проверки подписи утверждения SAML. Мой код практически идентичен примеру verify4.c на веб-странице xmlsec.

Я ссылаюсь на библиотеку xmlsec-openssl, поэтому использую openssl в качестве механизма шифрования.

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

Тем не менее, подпись считается действительной, если она подписана ЛЮБЫМ сертификатом, который может быть проверен openssl. Это означает, что кто-то может подделать ответ SAML, просто купив сертификат у доверенного корневого ЦС и используя его для подписи любого ответа, который он хочет.

Кроме того, инструмент командной строки xmlsec1, предоставляемый с библиотекой, похоже, делает то же самое:

xmlsec1 --verify --dtd-file saml.dtd --pubkey-cert-pem my_cert.cer sample_saml_assertion.xml

...
OK
SignedInfo References (ok/all): 1/1
Manifests References (ok/all): 0/0

На самом деле, в идеальном мире я был бы рад любому действительному ключу подписи, который будет использоваться, если бы я мог определить предмет ключа и, следовательно, подтвердить, что он был подписан организацией, которую я ожидал. Это упростило бы ситуацию, когда отправитель ответов SAML изменил свой ключ подписи. Но я не смог найти простой способ извлечь детали сертификата, который использовался для проверки подписи.

В противном случае я могу заставить его принимать только те сертификаты, которые я указал при проверке подписи?

1 ответ

Решение

При написании вопроса я понял, что не пробовал --print-debug опция для xmlsec1. Когда я попробовал это, я обнаружил, что он действительно печатает тему и издателя сертификата, который использовался для проверки подписи.

Это привело меня к осознанию того, что информация должна присутствовать, поэтому вопрос заключается в том, как получить к ней доступ. Прослеживая код, я смог написать этот небольшой фрагмент, который добивается цели:

/* If signature is valid, then the list dsigCtx->signKey contains
   the signing key, data dsigCtx->signKey->dataList contains the certificate */
xmlSecPtrListPtr keyDataList = dsigCtx->signKey->dataList;

/* Iterate through the data list to find the X509 cert */
xmlSecSize n = xmlSecPtrListGetSize(keyDataList);
xmlSecSize i;
for (i=0; i<n; i++) {
    xmlSecKeyDataPtr item = xmlSecPtrListGetItem(keyDataList, i);
    if (xmlSecKeyDataIsValid(item) && xmlSecKeyDataCheckId(item, xmlSecOpenSSLKeyDataX509Id)) {

        /* Extract openssl cert */
        X509* cert = xmlSecOpenSSLKeyDataX509GetKeyCert(item);
        char cn_buff[256];
        if(cert != NULL) {
            /* Get the CN */
            X509_NAME * subject_name = X509_get_subject_name(cert);
            int nid_cn = OBJ_txt2nid("CN");
            X509_NAME_get_text_by_NID(subject_name, nid_cn, cn_buff, 255);

            /* Here you would compare it to the expected certificate */
            fprintf(stdout, "CN=%s\n", cn_buff);
        } else {
            fprintf(stdout, "Failed to obtain signing key cert\n");
        }
    }
}

Это кажется очень сложным способом получения чего-то столь фундаментального, поэтому я уверен, что должен быть более легкий путь.

Другие вопросы по тегам