求助:关于删除数字证书,对Microsoft的Platform SDK: Security比较熟悉的大侠请进,谢谢!

sct 长沙思远科技 开发组长/高级工程师/技术专家  2004-05-05 08:35:17
我的一个涉及用数字证书实现加密等操作的程序中要实现一个功能:
删除用户已经安装的数字证书,
我是用CertDuplicateCertificateContext来实现的,
当证书是他人的只包含其公钥的证书时,没有什么问题;
但是当证书是自己的包含私钥的证书时,相应的私钥没有被删掉;

在安装包含私钥证书的时候,会在系统目录(XP,2000应该类似)
C:\Documents and Settings\Administrator\
Application Data\Microsoft\SystemCertificates\My\Certificates
下产生一文件A

C:\Documents and Settings\Administrator\
Application Data\Microsoft\SystemCertificates\My\Keys
下产生一文件B
用CertDuplicateCertificateContext来删除证书时,
只是删除了文件A,而B文件尚在,
为了避免混乱,我希望我的程序在删除证书的同时删除相应的私钥,
但是我在Platform SDK: Security却找不到可用的函数,
函数CryptDestroyKey是销毁私钥,但这是另外一个概念,它并不会删除掉文件B,
哪位大侠对这方面了解多一些,请给我一些建议和帮助,谢谢!

------------------------------------------------------------------
我试了一下,在Windows的IE中删除证书时,相应的私钥文件也没有被删除掉。

...全文
379 20 点赞 打赏 收藏 举报
写回复
20 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
huchengyu 2004-07-06
快帮帮忙吧,我继续关注
  • 打赏
  • 举报
回复
sct 2004-05-13
主要的问题是:
我的程序中要用到函数
CryptUIDlgSelectCertificateFromStore
它的Requirements是:
Client: Included in Windows XP.
Server: Included in Windows Server 2003.
Header: Declared in CryptuiAPI.h.
Library: Use CryptUI.lib.

在2000中能编译通过,但是就是运行不了,老是无法定位某某函数于动态链接库,

当初是无法定位程序输入点CryptUIDlgSelectCertificateFromStore
于动态链接CRYPTUI.dll上,

当我把cryptui.dll、crypt32.dll和程序放到一起时,又变成了:
无法定位程序输入点CryptBinaryToStringA于动态连接库CRYPT32.dll,

我于是用VC的Depends工具查看crypt32.dll又关联到了哪些dll,
把这些dll也和程序放到一起,这回变成了:
无法定位程序输入点I_CryptReadTrustedPublisherDWORDValueFromRegistry
于动态连接库 CRYPT32.dll,
这回我就不知如何办了?

(并且一直让我迷惑不解的是:
当我把cryptui.dll、crypt32.dll和程序放到一起时,
怎么我的程序在有的2000上可以运行,在另外的却不可以)

不知ahu9870(阿胡9870) 兄有没有解决的办法?

------------------------
我正准备写报告,写好后把程序和报告给ahu9870(阿胡9870)兄一份吧,
其实我这个系统没做多少东西,就是进行加密、签名等安全处理,然后就是传输了。
  • 打赏
  • 举报
回复
sct 2004-05-13
还有就是,
要显示证书信息,必须把CERT_INFO 中的东东转为字符串?
但是

typedef struct _CERT_INFO 中的成员不知如何显示出来啊

CertGetNameString只能取得一点点信息吧,

还有很多东西都不知怎么显出来?

看来哪种选择都挺麻烦的,唉!
  • 打赏
  • 举报
回复
ahu9870 2004-05-13
还有一种可行的办法是为 WIN2K 和 WINXP 发行各自版本的软件,即在编译时明确指定WIN_VER 为
windows 2000 _WIN32_WINNT>=0x0500

windows xp _WIN32_WINNT>=0x0501

并在程序中用不同的代码处理对应的功能。
  • 打赏
  • 举报
回复
sct 2004-05-13
我发现PSDK中有这种UI功能的两个函数,
CryptUIDlgViewContext和CryptUIDlgSelectCertificateFromStore
都是Included in Windows XP,

我看我可以用CertEnumCertificatesInStore来自己获取证书信息,
然后自己显示各个证书的信息让用户自己选择,

这里有一个问题就是:我事先并不知道证书库中会有几个证书,
而我要通过自己的窗口让用户选择证书,每个证书有一个单选按钮与其对应,
单选按钮的个数就变成动态的了,我不知道怎么在自己的窗口中动态地显示元素?
ahu9870(阿胡9870)兄应该知道吧,交交我吧,如果有例子就更好了,

我目前的时间不多了,挺忙的,还要写文档,我知道 ahu9870(阿胡9870)兄也很忙,
但还是希望 ahu9870(阿胡9870)兄帮帮我,谢谢啦!
  • 打赏
  • 举报
回复
sct 2004-05-11
"2。统一采用新版本的DLL,然后采用WIN系统更新的方式 更新WIN2K的DLL版本。"
----主要是CRYPTUI.dll或crypt32.dll由可能用到很多别的dll,
光更新这两个dll可能不行的

  • 打赏
  • 举报
回复
sct 2004-05-11
"我想你统一用PSDK2003FEB,
而且把PSDK的库和头文件目录放在VC默认文件的前面,"
---这一步我做了,还是解决不了!

"发行时把PSDK的可重分配文件打包进去,"
---PSDK的可重分配文件?在哪里?这个我不清楚,请指点,谢谢!~
  • 打赏
  • 举报
回复
ahu9870 2004-05-10
你提到的
“最好不要告诉我:要更新2000中的这个CRYPTUI.dll,
因为我试图更新过,更新不了,文件正在使用...”

的问题,应当按照 "WIN系统更新的方式" 进行更新。即

1。如果这是一个不受保护的DLL,打包系统会进行处理,使其在系统重启自动更新;

2。如果这是一个受保护的DLL,应当参照 M$ 的相关文档 按照 "WIN系统更新的方式" 进行更新,说白了,就是替换掉 DLLCACHE 中的DLL,然后系统会强行把原来的DLL还原为新的DLL。
  • 打赏
  • 举报
回复
ahu9870 2004-05-10
我想你统一用PSDK2003FEB,而且把PSDK的库和头文件目录放在VC默认文件的前面,发行时把PSDK的可重分配文件打包进去,应当可以解决发行DLL版本不一致的问题。

如果还是不能解决,试一下下面方法之一:

1。对用到的API采用动态链接,即LoadLibrary()->GetProcAddress(),当然会比较麻烦;

2。统一采用新版本的DLL,然后采用WIN系统更新的方式 更新WIN2K的DLL版本。
  • 打赏
  • 举报
回复
ahu9870 2004-05-10
以下例子会显示然后删除个人证书目录下遇到的第一个证书的私钥,但并不会对证书标记私钥已删除。你可以从通常的私钥存放位置
%Documents and Settings%\<User Account>\Application Data\Microsoft\Crypto\RSA\<SID>
观察到确实已被删除了。其它问题只好你自己解决了。例子没有必要的错误处理!

// deletepk.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <tchar.h>
#include <stdio.h>
#include <atlbase.h>
#include <windows.h>

#pragma warning (disable : 4192)

//
// Import TLB from DLL
//
// Note: Make sure either you have the DLL in the current directory, or point
// it to the correct directory on you drive.
//
#import "capicom.dll"

//
// Use CAPICOM namespace.
//
using namespace CAPICOM;

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Module: main()

Remark: Entry point of CAPICOM Store C++ sample.

-----------------------------------------------------------------------------*/

int __cdecl _tmain (int argc, _TCHAR * argv[])
{
HRESULT hr = S_OK;

//
// Initialize COM library.
//
CoInitialize(0);

try
{
//
// Open current user My store.
//
_bstr_t bstrName = _T("My");
IStorePtr pIStore(__uuidof(Store));

if (FAILED(hr = pIStore->Open(CAPICOM_CURRENT_USER_STORE,
bstrName,
CAPICOM_STORE_OPEN_READ_ONLY)))
{
ATLTRACE(_T("Error [%#x]: pIStore->Open() failed at line %d.\n"), hr, __LINE__);
throw hr;
}

//
// Display all certificate in the store.
//
IUnknownPtr pIUnknown;
IEnumVARIANTPtr pIEnum;
_variant_t pDisp;
ULONG ulFetched;

//
// Get _NewEnum of Certificates collection.
//
if (FAILED(hr = pIStore->Certificates->get__NewEnum(&pIUnknown)))
{
ATLTRACE(_T("Error [%#x]: pIStore->Certificates->get__NewEnum() failed at line %d.\n"), hr, __LINE__);
throw hr;
}

//
// Get IEnumVARIANT interface of _NewEnum.
//
if (FAILED(hr = pIUnknown->QueryInterface(IID_IEnumVARIANT, (void **) &pIEnum)))
{
ATLTRACE(_T("Error [%#x]: pIUnknown->QueryInterface() failed at line %d.\n"), hr, __LINE__);
throw hr;
}

//
// Now loop through all items in the collection.
//
if (pIEnum->Next(1, &pDisp, &ulFetched) == S_OK)
{
//
// Display the certificate.
//
if (FAILED(hr = ((ICertificate2Ptr) pDisp.pdispVal)->Display()))
{
ATLTRACE(_T("Error [%#x]: ((ICertificatePtr) pDisp.pdispVal)->Display() failed at line %d.\n"), hr, __LINE__);
throw hr;
}


if (FAILED(hr = ((ICertificate2Ptr) pDisp.pdispVal)->PrivateKey->Delete()))
{
ATLTRACE(_T("Error [%#x]: Deleting failed at line %d.\n"), hr, __LINE__);
throw hr;
};

}
pDisp.Clear();
}


catch (_com_error e)
{
hr = e.Error();
ATLTRACE(_T("Error [%#x]: %s.\n"), hr, e.ErrorMessage());
}

catch (HRESULT hr)
{
ATLTRACE(_T("Error [%#x]: CAPICOM error.\n"), hr);
}

catch(...)
{
hr = CAPICOM_E_UNKNOWN;
ATLTRACE(_T("Unknown error.\n"));
}

CoUninitialize();

return (int) hr;
}

  • 打赏
  • 举报
回复
sct 2004-05-10
上一个问题我已经解决了,
现在剩下的问题就只有如何使我的程序在不同的Windows系统下运行了,
关于这个问题我以前发过一个帖,
虽然已经结帖,但是问题并没有解决,
麻烦你帮我看看:
------------------------------------
CSDN - 专家门诊 - VC/MFC 基础类问题
主  题: 如何使我的程序在2000中也能运行?我的程序用到了一个XP系统文件CRYPTUI.dll,XP的这个dll比2000中的要新,现在我的程序在2000中无法运行,

http://expert.csdn.net/Expert/topic/3023/3023785.xml?temp=3.786868E-02
------------------------------------
主要是我的程序用到了
#pragma comment(lib,"Crypt32.lib")
#pragma comment(lib,"CryptUI.lib")
而XP中CRYPTUI.dll、crypt32.dll的版本与2000中不同,
导致我的程序在2000中有的可以运行,有的不可以运行(我在不同的机子上试过)。

我把用到的dll和我的执行程序放到了一起,
但还是出现无法定位......于动态连接库CRYPTUI.dll或crypt32.dll这类问题,
以前是
无法定位程序输入点CryptUIDlgSelectCertificateFromStore
于动态链接库CRYPTUI.dll上。
现在又有
无法定位程序输入点CryptBinaryToStringA于动态连接库 CRYPT32.dll

弄得我头都大了,再次麻烦 ahu9870(阿胡9870)兄了,谢谢!




  • 打赏
  • 举报
回复
sct 2004-05-10
考虑再三,我决定放弃删除包含私钥的数字证书,改而严格地将证书安装到默认的存储区,
我之前安装证书时将其他用户的证书也像自己的证书一样安装到“个人”存储区,
通过下面的代码我就可以选择数字证书:
HCERTSTORE hCertStore;

if(!(hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"my")))
{
AfxMessageBox("无法打开“MY”证书库!");
return 0;
}

LPCWSTR pwszTitle = L"查看数字证书";
LPCWSTR pwszDisplayString = L"请选择您要查看的数字证书,点击\"查看证书(V)\"按钮进行查看!";

CryptUIDlgSelectCertificateFromStore(
hCertStore,
NULL,
pwszTitle,
pwszDisplayString,
CRYPTUI_SELECT_LOCATION_COLUMN,
0,
NULL);

现在安装他人的数字证书时我按照默认值进行安装,会安装到“其他人”存储区,
通过Internet选项的内容-证书-其他人,可以看到所安装的证书,但是我在自己的程序中
去无法查看这一证书,我在CertOpenStore中指定打开“Other”证书库,
但是调用CryptUIDlgSelectCertificateFromStore来显示这一证书库的证书时,
却什么也看不到,“其他人”存储区应该是对应“Other”,怎么会看不到呢?
困惑中,只好再次麻烦 ahu9870(阿胡9870)指点一下,谢谢!
  • 打赏
  • 举报
回复
sct 2004-05-09
不知道增加CAPICOM的代价有多大?
在自己的程序文件夹里加Capicom.dll这个文件就可以了吗?
我现在是想先把准确删除与数字证书对应的私钥这项功能完成,
之后有时间再分析一下CAPICOM是如何实现的,看能否自己用代码实现之。
可是现在我还不知道如何用CAPICOM来完成我的任务?
以前没接触过这些东东,请请ahu9870(阿胡9870)兄指点,谢谢!
  • 打赏
  • 举报
回复
sct 2004-05-09
我看了CryptAcquireContext() with dwFlags = CRYPT_DELETEKEYSET,
它是把All key pairs in the key container are also destroyed,
而我只是想把与所删除的证书对应的那个私钥删除;
-------------------------------------------------
用CryptExportKey()函数,传递 CRYPT_DESTROYKEY 标志给它,
---不好用这个函数吧,获取私钥参数HCRYPTKEY hKey都是个问题,
并且CRYPT_DESTROYKEY,
This flag destroys the original key in the OPAQUEKEYBLOB.
This flag is available in Schannel CSPs only.
-------------------------------------------------
CAPICOM 的 PrivateKey.Delete怎么用啊?
我现在要删除数字证书,参数只有CryptUIDlgSelectCertificateFromStore
返回的一个PCCERT_CONTEXT,如何与PrivateKey联系起来啊,
Platform SDK: Security中关于CAPICOM的例子好少啊,
我基本上都没看到什么例子,都只是一些Objects以及它们的属性、函数,
-------------------------------------------------
请ahu9870(阿胡9870)兄指点,谢谢!


  • 打赏
  • 举报
回复
ahu9870 2004-05-09
抱歉,上面转载的讨论组的回答是不行的(见讨论组中我的答复)。我已经搜索了M$相关讨论组和文档,发现以前几个类似的提问均没有解答:

http://www.google.com/groups?as_q=api&num=50&as_scoring=r&hl=zh-CN&inlang=zh-CN&ie=GB2312&oe=GB2312&btnG=Google%CB%D1%CB%F7&as_epq=private+key&as_oq=delete&as_eq=&as_ugroup=microsoft.public.*&as_usubject=&as_uauthors=&as_umsgid=&lr=&as_drrb=q&as_qdr=&as_miny=1981&as_minm=5&as_mind=12&as_maxy=2004&as_maxm=5&as_maxd=8

看来现在唯一的可行办法就是用
CAPICOM
了。如果你有精力可以分析一下CAPICOM是如何实现的,然后自己用代码实现之。因为如果只是为了删除私钥一项功能而增加一个较大的控件代价太大。
  • 打赏
  • 举报
回复
sct 2004-05-08
我试一试
  • 打赏
  • 举报
回复
ahu9870 2004-05-07
替你在新开通的 microsoft.public.security.crypto 新闻组上发了个帖子,得到的回答是:

You can use CryptAcquireContext() with dwFlags = CRYPT_DELETEKEYSET

If you also want to removed the corresponding certificate from the cert store programatically
CertDeleteCertificateFromStore()

- Mitch
  • 打赏
  • 举报
回复
ahu9870 2004-05-07
你可以试试 对私钥句柄 用
CryptExportKey()
函数,传递 CRYPT_DESTROYKEY 标志给它。
  • 打赏
  • 举报
回复
sct 2004-05-07
Help!
  • 打赏
  • 举报
回复
ahu9870 2004-05-07
发现可用 CAPICOM 的
PrivateKey.Delete
方法可以做到删除私钥。见MSDN文档。

CAPICOM 在 PSDK 中,下载地址是
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/default.htm?p=/msdownload/platformsdk/sdkupdate/psdkredist.htm
  • 打赏
  • 举报
回复
相关推荐
发帖
云安全
加入

4377

社区成员

云计算 云安全相关讨论
申请成为版主
帖子事件
创建了帖子
2004-05-05 08:35
社区公告
暂无公告