问题描述
我有一个证书,需要在 http 请求的标头中发送。这是我获得证书的方式:
PCCERT_CONTEXT cert = nullptr;
wstring store = // store name
wstring subjectName = // subject name
HCERTSTORE hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYstem,NULL,CERT_SYstem_STORE_CURRENT_USER,store.c_str());
cert = CertFindCertificateInStore(
hStoreHandle,X509_ASN_ENCODING,CERT_FIND_SUBJECT_STR,subjectName.c_str(),NULL);
我需要将它作为自定义标头发送,因为位于我的服务前面的负载均衡器会在转发请求之前去除证书标头 ["X-ARR-CLIENTCERT"]。我相信我需要发送 cert->pbCertEncoded,但在服务器上,我无法对其进行解码并将其转换回 X509Certificate2。
这是我在客户端上尝试的:
request.headers().add("client-cert",cert->pbCertEncoded);
在服务器上:
var headerCert = Request.Headers["client-cert"];
byte[] certdata = Convert.FromBase64String(headerCert);
X509Certificate2 cert = new X509Certificate2(certdata);
服务器上的请求头是非空的。但它无法将其解析回 X509Certificate2。
我在客户端上尝试了另一件事。拿到证书后,我将其转换为字符串
DWORD size = 0;
CryptBinaryToString(cert->pbCertEncoded,cert->cbCertEncoded,CRYPT_STRING_BASE64,&size);
LPWSTR outstring = new TCHAR[size];
CryptBinaryToString(cert->pbCertEncoded,outstring,&size);
如果我尝试在标头中发送 outstring,它会抱怨:
WinHttpAddRequestHeaders: 87: The parameter is incorrect.
但是当我获取 outstring 的内容并尝试在服务器上解析它时,它会解码回正确的证书。这告诉我在标题中传递 cert->pbCertEncoded 时我没有做正确的事情。也许我需要重新编码或以某种方式转换它以便服务器可以正确解析它?我很感激任何帮助。谢谢!
我的客户端使用 C++,服务器使用 .NET。我正在使用 cpprestsdk 在 http 请求中发送证书。
解决方法
pbCertEncoded
是证书的 ASN.1 编码表示。查找实例 here。
因此您必须将字节编码为 base64,例如:
#include <Wincrypt.h>
#pragma comment (lib,"Crypt32.lib")
int ToBase64Crypto(const BYTE* pSrc,int nLenSrc,char* pDst,int nLenDst )
{
DWORD nLenOut = nLenDst;
BOOL fRet = CryptBinaryToString(
(const BYTE*)pSrc,nLenSrc,CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,pDst,&nLenOut
);
if (!fRet) {
nLenOut=0; // failed
}
return (nLenOut);
}