调用函数去安装自签的根证书

前言

​ 使用程序去安装根证书的目的是:使用自签的证书给软件进行签名,安装根证书之后,电脑就会信任该自签名软件,不会进行拦截。当然可以的话,掏钱买证书比较好。我见过有些软件会安装根证书,但都是key驱动或者CA厂家。安装根证书需要用户手动点击确定按钮,就好比你是否同意我们的协议。

​ 以下的证书都是cer证书,base64内容。其他格式可以转成cer格式

证书的安装

​ 证书安装需要几个步骤,

1. 读取证书内容
2. 解析证书内容,并得到证书上下文
3. 添加或删除以及判断证书是否安装

读取证书内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
char* readFile(int* len)
{
int length = 0;
ifstream file("localhost.cer");
if (!file.is_open())
{
std::cout << "open file fail" << endl;
}
file.seekg(0, std::ios::end); // go to the end
length = file.tellg(); // report location (this is the length)
file.seekg(0, std::ios::beg); // go back to the beginning
char* buffer = new char[length]; // allocate memory for a buffer of appropriate dimension
file.read(buffer, length); // read the whole file into the buffer
file.close();

*len = length;
return buffer;
}

解析证书并得到证书上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
///解码证书
PCCERT_CONTEXT DecodeCert(LPBYTE lpCertData, ULONG ulDataLen)
{
PCCERT_CONTEXT pCertContext = NULL;

ULONG ulFlag = CRYPT_FIRST;
ULONG ulContainerNameLen = 512;
CHAR csContainerName[512] = { 0 };
BOOL bFoundContainer = FALSE;

if (!lpCertData || ulDataLen == 0)
{
return pCertContext;
}

// 由证书链创建一个证书库
HCERTSTORE hCertStore = NULL;

CRYPT_DATA_BLOB dataBlob = { ulDataLen, lpCertData };
DWORD pdwContentType = CERT_QUERY_CONTENT_CERT;
//尝试使用所有格式去解析证书
CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &dataBlob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL,
NULL, &pdwContentType, NULL, NULL, &hCertStore, NULL, (const void**)&pCertContext);

if (NULL == hCertStore)
{
return NULL;
}
// 得到第一个证书内容
if (pCertContext == NULL)
{
pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext);
}

//释放证书库
if (hCertStore)
{
CertCloseStore(hCertStore, 0);
hCertStore = NULL;
}

return pCertContext;
}

添加证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool SaveCert(BYTE* cert, int length)
{
bool ret = false;
PCCERT_CONTEXT pCertContext = NULL;
//得到证书的上下文
pCertContext = DecodeCert(cert, length);
HCERTSTORE hRootCertStore = CertOpenSystemStore(NULL, L"ROOT");
if (hRootCertStore != NULL && pCertContext != NULL)
{
//往证书存储区中添加证书
ret = CertAddCertificateContextToStore(hRootCertStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING,NULL);
//释放证书库
CertCloseStore(hRootCertStore, 0);
//释放证书上下文
CertFreeCertificateContext(pCertContext);
}
return ret;
}

需要注意,Windows会弹出对话框,类似于以下图:

判断是否有证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
bool HasCert(BYTE* cert, int length)
{

bool ret = false;
PCCERT_CONTEXT pCertContext = NULL;

pCertContext = DecodeCert(cert,length);


if (pCertContext != NULL)
{

HCERTSTORE hRootCertStore = CertOpenSystemStore(NULL, L"ROOT");

if (hRootCertStore != NULL)
{

PCCERT_CONTEXT certcontext = CertFindCertificateInStore(hRootCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_EXISTING, pCertContext, NULL);

if (certcontext != NULL)
{

ret = true;
CertFreeCertificateContext(certcontext);

}

}

CertFreeCertificateContext(pCertContext);

}

return ret;

}

删除根证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
bool DeleteCert(BYTE* cert, int length)
{
bool ret = true;
PCCERT_CONTEXT pCertContext = NULL;

pCertContext = DecodeCert(cert, length);
if (pCertContext != NULL)
{

HCERTSTORE hRootCertStore = CertOpenSystemStore(NULL, L"ROOT");
if (hRootCertStore != NULL)
{
PCCERT_CONTEXT certcontext = CertFindCertificateInStore(hRootCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_EXISTING, pCertContext, NULL);
if (certcontext != NULL)
{
ret = CertDeleteCertificateFromStore(certcontext);
int error = GetLastError();
std::cout << error << endl;
}
}

CertFreeCertificateContext(pCertContext);
}
return ret;
}

同安装证书一样,Windows会弹出对话框让用户确认:

结尾

​ 好久之前写的代码了,以前因为项目需要给用户电脑安装根证书,但是后来发现不需要了,公司有现成的付费代码签名证书。

评论