我使用xmlsec库来验证SAML断言的签名。我的代码几乎与xmlsec网页上提供的verify4.c示例相同。
我正在连接xmlsec-openssl lib,所以使用openssl作为加密引擎。
我原以为xmlsec只有在用我加载到密钥管理器中的某个特定证书签名时才会认为签名有效。
但是,如果使用可由openssl验证的任何证书进行签名,则签名似乎被视为有效。这意味着有人可以通过从受信任的根CA购买证书并使用它来签署他们想要的任何响应来伪造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响应的发件人更改其签名密钥时,这将简化问题。但我无法找到一种简单的方法来提取用于验证签名的证书的详细信息。
如果不这样做,我可以让它只接受我在验证签名时指定的证书吗?
答案 0 :(得分:0)
在写这个问题时,我意识到我没有尝试过xmlsec1的--print-debug
选项。当我尝试时,我发现它确实打印了用于验证签名的证书的主题和颁发者。
这让我意识到信息必须存在,所以这是一个如何访问它的问题。通过代码跟踪,我能够编写这个小技巧片段,以实现这一目的:
/* 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");
}
}
}
这似乎是一种非常复杂的方式来获得如此根本的东西,所以我相信必须有一种更简单的方法。