解决ClickOnce签名过期问题(转载)
原文地址:http://www.cnblogs.com/xuhaibiao/archive/2009/06/23/1509692.html
场景:用于生产环境的项目进行系统升级,在发布ClickOnce过程中发现签名已过期,现场工程师重新生成了一个签名,然后进行发布,发布完成后,所有客户端无法更新,提示签名错误。
问题:VS2005做年签名只有一年期限,所以很容易在维护期内就过期了,如果新做签名结果会造成客户端验证签名出错无法更新。
解决办法:
1、新做一个签名,使用新的签名做ClickOnce,所有客户端将原来程序删除,重新使用新的ClickOnce安装程序进行安装。
(此方法太可耻了,如果再有升级的话,可能还会有这问题,同时ClickOnce也得改名叫ClickOneYear了)。
2、利用原有签名,延长有效时间。
(中文)http://support.microsoft.com/kb/925521/zh-cn
(英文)http://support.microsoft.com/kb/925521/en-us
方法 1
更新客户端计算机 Microsoft 安装 ClickOnce 应用程序,.NET Framework 2.0 Service Pack 1 (SP1) 或更高版本。
Windows Vista
.NET Framework 3.5 或.NET Framework 3.5 SP 1 应用。
注意:.NET Framework 3.5 包含许多新功能,生成在.NET Framework 2.0 版时以增量方式和 3.0。.NET Framework 3.5 包括.NET Framework 2.0 SP1 和.NET Framework 3.0 SP1。
下列文件已可从 Microsoft 下载中心下载:
立即下载.NET Framework 3.5 Service Pack 1 包。
有关如何下载 Microsoft 支持文件的详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
微软已对此文件进行病毒扫描。Microsoft 使用该文件投递日期时可用的最新的病毒检测软件。存储在安全增强型服务器上的该文件,帮助防止对文件进行任何未经授权的更改。
Windows XP
.NET Framework 2.0 SP1 或.NET Framework 2.0 Service Pack 2 (SP2) 应用。
下面是一些可从 Microsoft 下载中心下载的文件:
立即下载.NET Framework 2.0 Service Pack 1 (x86) 包。
立即下载.NET Framework 2.0 Service Pack 1 (64) 包。
立即下载.NET Framework 2.0 Service Pack 2 包。
有关如何下载 Microsoft 支持文件的详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
微软已对此文件进行病毒扫描。
方法 2
卸载您使用过期的证书注册的 ClickOnce 应用程序。
方法 3
创建命令行程序集更新证书。
Microsoft 提供的编程示例仅用于说明,没有任何明示或暗示的担保。这包括但不限于适销性或特定用途适用性的暗示担保。本文假定您熟悉所演示的编程语言和用于创建和调试过程的工具。Microsoft 的支持工程师可以帮助解释某个特定过程的功能。但是,他们不会修改这些示例以提供额外的功能或构建过程以满足您的特定要求。
- 在 Visual Studio 2005 中,在文件菜单上单击新建,然后单击项目。
- 单击Visual C++ Win32 控制台应用程序中的名称框中,键入RenewCert和,然后单击确定。
- 在Win32 应用程序向导对话框中,单击完成。
- 在 RenewCert.cpp 文件中,用下面的代码替换现有代码:
- #include "stdafx.h"
- void ReadPFXFile(LPCWSTR fileName, CRYPT_DATA_BLOB *pPFX)
- {
- HANDLE hCertFile = NULL;
- DWORD cbRead = 0;
- DWORD dwFileSize = 0, dwFileSizeHi = 0;
- hCertFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
- dwFileSize = GetFileSize(hCertFile, &dwFileSizeHi);
- pPFX->pbData = (BYTE *) CryptMemAlloc(dwFileSize*sizeof(BYTE));
- pPFX->cbData = dwFileSize;
- ReadFile(hCertFile, pPFX->pbData, pPFX->cbData, &cbRead, NULL);
- CloseHandle(hCertFile);
- }
- void GetPrivateKey(CRYPT_DATA_BLOB pPFX, LPCWSTR szPassword, HCRYPTPROV *hCPContext)
- {
- HCERTSTORE hCertStore = NULL;
- PCCERT_CONTEXT hCertContext = NULL;
- DWORD dwKeySpec = AT_SIGNATURE;
- BOOL bFreeCertKey = TRUE;
- hCertStore = PFXImportCertStore(&pPFX, szPassword, CRYPT_EXPORTABLE);
- hCertContext = CertEnumCertificatesInStore(hCertStore, NULL);
- CryptAcquireCertificatePrivateKey(hCertContext, 0, NULL, hCPContext, &dwKeySpec, &bFreeCertKey);
- CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
- }
- void PrintContainerName(HCRYPTPROV hCPContext)
- {
- DWORD containerNameLen = 0;
- CHAR *szContainerName = NULL;
- CryptGetProvParam(hCPContext, PP_CONTAINER, NULL, &containerNameLen, 0);
- szContainerName = (CHAR *)CryptMemAlloc(sizeof(BYTE)*containerNameLen);
- CryptGetProvParam(hCPContext, PP_CONTAINER, (BYTE *)szContainerName, &containerNameLen, 0);
- printf("This certificate's container name is: %s", szContainerName);
- }
- void MakeNewCert(HCRYPTPROV hCPContext, LPCWSTR szCertName, LPCWSTR szPassword, CRYPT_DATA_BLOB *pPFX)
- {
- CERT_NAME_BLOB certNameBlob = {0,NULL};
- PCCERT_CONTEXT hCertContext = NULL;
- SYSTEMTIME certExpireDate;
- HCERTSTORE hTempStore = NULL;
- CertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szCertName, CERT_OID_NAME_STR, NULL, NULL, &certNameBlob.cbData, NULL);
- certNameBlob.pbData = (BYTE *)CryptMemAlloc(sizeof(BYTE)*certNameBlob.cbData);
- CertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szCertName, CERT_OID_NAME_STR, NULL, certNameBlob.pbData, &certNameBlob.cbData, NULL);
- GetSystemTime(&certExpireDate);
- certExpireDate.wYear += 5;
- hCertContext = CertCreateSelfSignCertificate(hCPContext, &certNameBlob, 0, NULL, NULL, NULL, &certExpireDate, NULL);
- hTempStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, 0);
- CertAddCertificateContextToStore(hTempStore, hCertContext, CERT_STORE_ADD_NEW, NULL);
- PFXExportCertStoreEx(hTempStore, pPFX, szPassword, NULL, EXPORT_PRIVATE_KEYS);
- pPFX->pbData = (BYTE *)CryptMemAlloc(sizeof(BYTE)*pPFX->cbData);
- PFXExportCertStoreEx(hTempStore, pPFX, szPassword, NULL, EXPORT_PRIVATE_KEYS);
- CryptMemFree(certNameBlob.pbData);
- CertCloseStore(hTempStore, CERT_CLOSE_STORE_FORCE_FLAG);
- CertFreeCertificateContext(hCertContext);
- }
- void WritePFX(CRYPT_DATA_BLOB pPFX, LPCWSTR szOutputFile)
- {
- HANDLE hOutputFile = NULL;
- DWORD cbWritten = 0;
- hOutputFile = CreateFile(szOutputFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
- WriteFile(hOutputFile, pPFX.pbData, pPFX.cbData, &cbWritten, NULL);
- CloseHandle(hOutputFile);
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- LPCWSTR szCertFileName = NULL;
- CRYPT_DATA_BLOB pPFX;
- LPCWSTR szPassword = NULL;
- HCRYPTPROV hCPContext = NULL;
- LPCWSTR szCertName = L"CN=NewCert";
- CRYPT_DATA_BLOB pPfxOutputBlob = {0,NULL};
- LPCWSTR szOutFile = NULL;
- // Parse the command line.
- if(argc == 1)
- {
- printf("renewcert <PFX File> <new cert filename> <new cert friendly name> [optional]<password>\n");
- printf("Example: renewcert oldcert.pfx newcert.pfx \"CN=MyNewCert\" MySuperSecretPassword");
- return 0;
- }
- if(argc >= 2)
- szCertFileName = argv[1];
- if(argc >= 5)
- szPassword = argv[4];
- // Uncomment this block to add <new cert filename> and <new cert friendly name> as parameters
- // NOTE: <new cert friendly name> must be of format "CN=<name>"
- if(argc >= 3)
- szOutFile = argv[2];
- if(argc >= 4)
- szCertName = argv[3];
- ReadPFXFile(szCertFileName, &pPFX);
- GetPrivateKey(pPFX, szPassword, &hCPContext);
- //PrintContainerName(hCPContext);
- // Uncomment this section to make a new PFX rather than just printing the container name.
- // Make sure you also uncomment the command line parameter section above.
- MakeNewCert(hCPContext, szCertName, szPassword, &pPfxOutputBlob);
- WritePFX(pPfxOutputBlob, szOutFile);
- // Clean up.
- CryptReleaseContext(hCPContext, 0);
- CryptMemFree(pPfxOutputBlob.pbData);
- CryptMemFree(pPFX.pbData);
- return 0;
- }
- 在 stdafx.h 文件中,用下面的代码替换现有代码:
- // stdafx.h : include file for standard system include files,
- // or project specific include files that are used frequently, but
- // are changed infrequently.
- //
- #pragma once
- #define WIN32_LEAN_AND_MEAN // Exclude rarely used material from Windows headers.
- #include <stdio.h>
- #include <tchar.h>
- #include <windows.h>
- #include <wincrypt.h>
- 在项目菜单上,单击属性以打开此项目的属性页。
- 展开链接器节点,然后单击输入。
- 附加依赖项,右边的空白窗口中单击,然后单击省略号按钮 (...) 到附加依赖项对话框中打开。
- 在空白的窗口中,键入Crypt32.lib,然后单击确定。
- 单击应用,然后单击确定以关闭属性页。
- 在生成菜单中,单击生成解决方案。
- 生成解决方案后,执行以下命令,以更新证书,请:
- renewcert <OldCertificate>.pfx <NewCertificate>.pfx \"CN=<NewCertificateName>\" <Password>
注意: <OldCertificate>是旧证书的占位符、 <NewCertificate>是新证书的占位符、 <NewCertificateName>是新的证书的名称的占位符和<Password>是密码的占位符。
更多信息
要重现此问题的步骤
- 启动 Visual Studio 2005。
- 在文件菜单上单击新建,然后单击项目。
- 单击C#单击Windows 应用程序,请在名称框中,键入WindowsApplication1 ,然后单击确定。
- 在解决方案资源管理器中,用鼠标右键单击WindowsApplication1,然后单击属性。
- 单击签名,并将不久即会过期的证书。
- 在解决方案资源管理器中,用鼠标右键单击WindowsApplication1,然后单击发布。
- 在要在其中发布该应用程序?页上,键入一个有效的 URL,然后单击下一步。
http://ServerName/FolderName
- 在应用程序是否将可脱机吗?页面上,单击相应的选项。
备注:
- 如果您想让用户从网络断开连接时运行该应用程序的用户,请单击是,此应用程序可联机或脱机。向导将在开始菜单上创建应用程序的快捷方式。
- 如果想要直接从发布位置运行该应用程序,则单击否,此应用程序只能联机使用。该向导不会在开始菜单上创建快捷方式。
- 单击下一步以继续。
- 单击完成以发布应用程序。
- 安装 ClickOnce 应用程序从 http://ServerName/ /publish.htmFolderName的 URL。
- 在证书过期后,请重复步骤 6 至 10 以重新发布应用程序。
- 尝试安装 ClickOnce 应用程序更新从 http://ServerName/ /publish.htmFolderName的 URL。
有此朋友发现过这样的问题,也知道解决办法,但如果机器上没装VC++可能操作起来也不方便,现编译完成一份,各位可以下载:
http://files.cnblogs.com/spymaster/RenewCert.rar
使用方法:到命令窗口,输入
renewcert <OldCertificate>.pfx <NewCertificate>.pfx \"CN=<NewCertificateName>\" <Password>
好了,新签名的有限期是5年。
3、项目之初就做一个长效的签名。
http://www.cnblogs.com/xuhaibiao/archive/2009/06/22/1508317.html
打开Microsoft .NET Framework 的SDK命令提示,按以下步骤操作:
1、创建一个自我签署的X.509证书(.cer)和一个.pvk私钥文件,用到makecert工具,命令如下:
makecert -r -n "CN= cncxz " -b 01/01/2005 -e 01/01/2018 -sv myselfName.pvk myselfName.cer
按提示设置私钥密码(也可以不使用密码)即可在当前目录生成相关文件
2、利用X.509证书(.cer)创建发行者证书 (.spc),用到cert2spc工具,命令如下:
cert2spc myselfName.cer myselfName.spc
3、从.pvk和.spc格式转换成.pfx格式,用到pvkimprt工具,命令如下:
pvkimprt -pfx myselfName.spc myselfName.pvk
按提示操作可导出.pfx证书,若第1步设置了私钥密码,此处需要输入验证
4、在vs项目的ClickOnce清单签名的证书设置处点击“从文件选择”浏览定位到第3步导出的.pfx证书,此处需要验证第3步中设置的证书私钥密码。
makecert工具和cert2spc工具.NET Framework自带,pvkimprt工具下载地址如下
http://download.microsoft.com/download/vba50/Utility/1.0/NT5/EN-US/pvkimprt.exe
如果以上下载链接有失效的,请到该地址下载:
http://download.csdn.net/detail/u012373717/8726827
解决ClickOnce签名过期问题(转载)的更多相关文章
- App 签名过期或泄露怎么办?别担心,Google 已经给出解决方案!
一.序 在将 App 发布到市场之前,很重要的一个步骤就是为 APK 进行签名,大部分时候,这个操作隐藏在了打包的流程中,而不被我们注意到. 签名的作用,除了证明 App 的所有权之外,还可以帮助 A ...
- 解决Chrome flash过期
解决Chrome flash过期的办法安装Adobe Flash Player PPAPI
- iPhone OS 开发 - 了解并解决代码签名问题
译者:Jestery 发表时间:2010-04-24浏览量:21082评论数:0挑错数:0 了解并解决代码签名问题 (为保持跟开发环境以及APPLE开发者社区网站结构对应,一些名词未作翻译) 绝大多数 ...
- [转载]解决clickonce不支持administer权限问题
转自ClickOnce deployment vs. requestedExecutionLevel = requireAdministrator ClickOnce方式部署应用简单方便,估计很多人都 ...
- Manifest XML signature is not valid(安装ClickOnce签名未通过验证)
转载:http://stackoverflow.com/questions/12826798/manifest-xml-signature-is-not-valid 安装时,我的问题: PLATFO ...
- 解决was6版本号过期问题
原创作品.出自 "深蓝的blog" 博客,欢迎转载.转载时请务必注明出处.否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong ...
- 使用Source Safe for SQL Server解决数据库版本管理问题(转载)
简介 在软件开发过程中,版本控制是一个广为人知的概念.因为一个项目可能会需要不同角色人员的参与,通过使用版本控制软件,可以使得项目中不同角色的人并行参与到项目当中.源代码控制使得代码可以存在多个版本, ...
- Server 2008 R2多用户远程桌面连接授权,解决120天过期问题
在工作中,我们往往需要远程服务器,经常会遇到以下这两个麻烦事. 一.远程桌面的连接数限制,超出系统就会提示超过连接数. 二.远程桌面连接时,同一个用户不能同时远程2个桌面连接. ----------- ...
- ubuntu google chrome 忽略证书错误 -- 解决自签名证书不支持的问题
ubuntu chrome 打开自签名的证书的服务器的https时,提示 Your connection is not private. 错误代码:NET::ERR_CERT_AUTHORITY_IN ...
随机推荐
- 说说Java中的枚举(一)
在实际编程中,往往存在着这样的“数据集”,它们的数值在程序中是稳定的,而且“数据集”中的元素是有限的.例如星期一到星期日七个数据元素组成了一周的“数据集”,春夏秋冬四个数据元素组成了四季的“数据集”. ...
- 新浪微博客户端(23)-计算Cell内控件的frame
DJStatusCellFrame.m #import "DJStatusCellFrame.h" #import "DJStatus.h" #import & ...
- Office Web Apps资源
http://www.cnblogs.com/poissonnotes/p/3277280.html#!comments http://www.cnblogs.com/poissonnotes/p/3 ...
- 字符串模拟赛T2
// source code from laekov for c0x17 #define PRID "fkqh" #include <cstdio> #include ...
- FineUI第五天---按钮控件
按钮控件 <x:Button runat="server" ID="按下" Text="按下"></x:Button> ...
- HXOI 2014 PSet 4 Day 1 一模04日1 题解
1. 最小花费(money.pas/c/cpp) 问题描述 在n个人中,某些人的银行账号之间可以互相转账.这些人之间转账的手续费各不相同.给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问 ...
- linux awk 内置函数详细介绍(实例)
这节详细介绍awk内置函数,主要分以下3种类似:算数函数.字符串函数.其它一般函数.时间函数 一.算术函数: 以下算术函数执行与 C 语言中名称相同的子例程相同的操作: 函数名 说明 atan2( y ...
- (部署新java程序,程序报错,需copy的一个包)——java使用siger 获取服务器硬件信息
mcat-siger.sh 查看是否安装siger rsync -aPuv /usr/lib64/libsigar-amd64-linux.so $i:/usr/lib64/ java使用siger ...
- 【Python】 Django 怎么实现 联合主键?
unique_together¶ Options.unique_together¶ Sets of field names that, taken together, must be unique: ...
- HTML5 manifest离线缓存
一.基本概念 离线缓存是HTML5新引入的技术,能够让你的Web应用程序指定哪些文件可以缓存在本地,使得你的网络断开时依然可以通过本地的缓存来进行访问浏览. 二.使用方法 1. MIME type 声 ...