原文地址: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 软件包。

 
 

立即下载.NET Framework 3.5 Service Pack 1 包。

有关如何下载 Microsoft 支持文件的详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:

119591如何从在线服务获得 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 知识库中相应的文章:

119591如何从在线服务获得 Microsoft 的支持文件

微软已对此文件进行病毒扫描。

方法 2

卸载您使用过期的证书注册的 ClickOnce 应用程序。

方法 3

创建命令行程序集更新证书。

Microsoft 提供的编程示例仅用于说明,没有任何明示或暗示的担保。这包括但不限于适销性或特定用途适用性的暗示担保。本文假定您熟悉所演示的编程语言和用于创建和调试过程的工具。Microsoft 的支持工程师可以帮助解释某个特定过程的功能。但是,他们不会修改这些示例以提供额外的功能或构建过程以满足您的特定要求。

  1. 在 Visual Studio 2005 中,在文件菜单上单击新建,然后单击项目
  2. 单击Visual C++ Win32 控制台应用程序中的名称框中,键入RenewCert和,然后单击确定
  3. Win32 应用程序向导对话框中,单击完成
  4. 在 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;
    
    }
    
  5. 在 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>
    
  6. 项目菜单上,单击属性以打开此项目的属性页。
  7. 展开链接器节点,然后单击输入
  8. 附加依赖项,右边的空白窗口中单击,然后单击省略号按钮 (...) 到附加依赖项对话框中打开。
  9. 在空白的窗口中,键入Crypt32.lib,然后单击确定
  10. 单击应用,然后单击确定以关闭属性页。
  11. 生成菜单中,单击生成解决方案
  12. 生成解决方案后,执行以下命令,以更新证书,请:
    renewcert <OldCertificate>.pfx <NewCertificate>.pfx \"CN=<NewCertificateName>\" <Password>

    注意: <OldCertificate>是旧证书的占位符、 <NewCertificate>是新证书的占位符、 <NewCertificateName>是新的证书的名称的占位符和<Password>是密码的占位符。

更多信息

要重现此问题的步骤

    1. 启动 Visual Studio 2005。
    2. 文件菜单上单击新建,然后单击项目
    3. 单击C#单击Windows 应用程序,请在名称框中,键入WindowsApplication1 ,然后单击确定
    4. 在解决方案资源管理器中,用鼠标右键单击WindowsApplication1,然后单击属性
    5. 单击签名,并将不久即会过期的证书。
    6. 在解决方案资源管理器中,用鼠标右键单击WindowsApplication1,然后单击发布
    7. 要在其中发布该应用程序?页上,键入一个有效的 URL,然后单击下一步
      http://ServerName/FolderName
    8. 应用程序是否将可脱机吗?页面上,单击相应的选项。

      备注:

      • 如果您想让用户从网络断开连接时运行该应用程序的用户,请单击是,此应用程序可联机或脱机。向导将在开始菜单上创建应用程序的快捷方式。
      • 如果想要直接从发布位置运行该应用程序,则单击否,此应用程序只能联机使用。该向导不会在开始菜单上创建快捷方式。
    9. 单击下一步以继续。
    10. 单击完成以发布应用程序。
    11. 安装 ClickOnce 应用程序从 http://ServerName/ /publish.htmFolderName的 URL。
    12. 在证书过期后,请重复步骤 6 至 10 以重新发布应用程序。
    13. 尝试安装 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签名过期问题(转载)的更多相关文章

  1. App 签名过期或泄露怎么办?别担心,Google 已经给出解决方案!

    一.序 在将 App 发布到市场之前,很重要的一个步骤就是为 APK 进行签名,大部分时候,这个操作隐藏在了打包的流程中,而不被我们注意到. 签名的作用,除了证明 App 的所有权之外,还可以帮助 A ...

  2. 解决Chrome flash过期

    解决Chrome flash过期的办法安装Adobe Flash Player PPAPI

  3. iPhone OS 开发 - 了解并解决代码签名问题

    译者:Jestery 发表时间:2010-04-24浏览量:21082评论数:0挑错数:0 了解并解决代码签名问题 (为保持跟开发环境以及APPLE开发者社区网站结构对应,一些名词未作翻译) 绝大多数 ...

  4. [转载]解决clickonce不支持administer权限问题

    转自ClickOnce deployment vs. requestedExecutionLevel = requireAdministrator ClickOnce方式部署应用简单方便,估计很多人都 ...

  5. Manifest XML signature is not valid(安装ClickOnce签名未通过验证)

    转载:http://stackoverflow.com/questions/12826798/manifest-xml-signature-is-not-valid 安装时,我的问题:  PLATFO ...

  6. 解决was6版本号过期问题

    原创作品.出自 "深蓝的blog" 博客,欢迎转载.转载时请务必注明出处.否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong ...

  7. 使用Source Safe for SQL Server解决数据库版本管理问题(转载)

    简介 在软件开发过程中,版本控制是一个广为人知的概念.因为一个项目可能会需要不同角色人员的参与,通过使用版本控制软件,可以使得项目中不同角色的人并行参与到项目当中.源代码控制使得代码可以存在多个版本, ...

  8. Server 2008 R2多用户远程桌面连接授权,解决120天过期问题

    在工作中,我们往往需要远程服务器,经常会遇到以下这两个麻烦事. 一.远程桌面的连接数限制,超出系统就会提示超过连接数. 二.远程桌面连接时,同一个用户不能同时远程2个桌面连接. ----------- ...

  9. ubuntu google chrome 忽略证书错误 -- 解决自签名证书不支持的问题

    ubuntu chrome 打开自签名的证书的服务器的https时,提示 Your connection is not private. 错误代码:NET::ERR_CERT_AUTHORITY_IN ...

随机推荐

  1. 转:Java NIO系列教程(九) Pipe

    Java NIO 管道是2个线程之间的单向数据连接.Pipe有一个source通道和一个sink通道.数据会被写到sink通道,从source通道读取. 这里是Pipe原理的图示: 创建管道 通过Pi ...

  2. (转)MFC中获得各个类的指针/句柄 ID的总结

    http://www.cnblogs.com/ylhome/archive/2009/10/06/1578478.html 一般我们使用的框架是VC提供的Wizard生成的MFC App Wizard ...

  3. EDdb 是ED数据

    eddb  是ED数据统计汇总软件的简称,用于统计汇总企事业单位的各类信息数据. 采用Excel界面,操作简单. 对各类信息数据,均可以自定义数据格式,通过internet联网,收集各类信息数据,并通 ...

  4. 读<你必须知道的.NET>IL指令笔记

    IL指令笔记: 1.newObj和initObj MSDN解释:newObj用于分配和初始化对象,而initObj用户初始化值类型 newObj解释: (1):从托管堆分配指定类型所需要的全部内存空间 ...

  5. Charm Bracelet

    Charm Bracelet Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Subm ...

  6. 小白科普之JavaScript的函数

    一 概述 1.1 函数声明 (1)function命令 函数就是使用function命令命名的代码区块,便于反复调用.这种声明方式叫做函数的声明(Function Declaration). func ...

  7. 新手选择使用 Linux 桌面的七个注意点

    导读 刚接触Linux桌面的用户该如何选择一款合适的Linux桌面环境呢?如果你习惯使用Windows或OS X,那么一想到要选择就让人犯难,那么你又该如何在十几个主要的Linux桌面.几十个次要的当 ...

  8. git clone报错

    (文章是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) Could not chdir to home directory /home/wangzheng: ...

  9. 纯Java获得本地MAC地址

    import java.net.*; public class Ipconfig{      public static void main(String[] arguments) throws Ex ...

  10. 异常详细信息: System.Data.SqlClient.SqlException:用户 'IIS APPPOOL\DefaultAppPool' 登录失败解决办法

    1.安全性---登录名---新建登录名 2.常规----搜索 3.添加SERVICE用户-- 4.服务器角色---勾上sysadmin: IIS中: 应用程序池---对应的程序池上右键---高级设置 ...