(转)创建X509证书,并获取证书密钥的一点研究

创建X509证书,并获取证书密钥的一点研究

作者:肖波

个人博客:http://blog.csdn.net/eaglet ; http://www.cnblogs.com/eaglet

2007/7 南京

 

背景

服务器SSL数字证书和客户端单位数字证书的格式遵循 X.509 标准。 X.509 是由国际电信联盟(ITU-T)制定的数字证书标准。为了提供公用网络用户目录信息服务, ITU 于 1988 年制定了 X.500 系列标准。其中 X.500 和 X.509 是安全认证系统的核心, X.500 定义了一种区别命名规则,以命名树来确保用户名称的唯一性; X.509 则为 X.500 用户名称提供了通信实体鉴别机制,并规定了实体鉴别过程中广泛适用的证书语法和数据接口, X.509 称之为证书。

   X.509 给出的鉴别框架是一种基于公开密钥体制的鉴别业务密钥管理。一个用户有两把密钥:一把是用户的专用密钥(简称为:私钥),另一把是其他用户都可得到和利用的公共密钥(简称为:公钥)。用户可用常规加密算法(如 DES)为信息加密,然后再用接收者的公共密钥对 DES 进行加密并将之附于信息之上,这样接收者可用对应的专用密钥打开 DES 密锁,并对信息解密。该鉴别框架允许用户将其公开密钥存放在CA的目录项中。一个用户如果想与另一个用户交换秘密信息,就可以直接从对方的目录项中获得相应的公开密钥,用于各种安全服务。

   最初的 X.509 版本公布于 1988 年,版本 3 的建议稿 1994 年公布,在 1995 年获得批准。本质上, X.509 证书由用户公共密钥与用户标识符组成,此外还包括版本号、证书序列号、CA 标识符、签名算法标识、签发者名称、证书有效期等。用户可通过安全可靠的方式向 CA 提供其公共密钥以获得证书,这样用户就可公开其证书,而任何需要此用户的公共密钥者都能得到此证书,并通过 CA 检验密钥是否正确。这一标准的最新版本 -- X.509 版本 3 是针对包含扩展信息的数字证书,提供一个扩展字段,以提供更多的灵活性及特殊环境下所需的信息传送。

   为了进行身份认证, X.509 标准及公共密钥加密系统提供了一个称作数字签名的方案。用户可生成一段信息及其摘要(亦称作信息“指纹”)。用户用专用密钥对摘要加密以形成签名,接收者用发送者的公共密钥对签名解密,并将之与收到的信息“指纹”进行比较,以确定其真实性。

   目前, X.509 标准已在编排公共密钥格式方面被广泛接受,已用于许多网络安全应用程序,其中包括 IP 安全( Ipsec )、安全套接层( SSL )、安全电子交易( SET )、安全多媒体 INTERNET 邮件扩展( S/MIME )等。

 

创建X509 证书

创建X509证书方法较多,在Windows 环境下大致总结了几中办法,

1)      通过CA获取证书,

2)      通过微软提供的makecert 工具得到测试证书

3)      编程的方法创建,.Net提供了 X509Certificate2 类,该类可以用于创建证书,但只能从RawData中创建,创建后无法修改除FriendlyName以外的任何属性。

 

我在互联网上找了很久,始终没有找到完全通过程序创建自定义的证书的方法。后来想了一个折中办法,就是用程序调用 makecert.exe 先生成一个证书,证书的一些参数如Subject,有效期,序列号等可以通过参数传入,然后把生成的证书文件读到Rawdata中,得到X509Certificate2 类型的证书对象。当然这种方法确实比较笨,必须要依赖外部进程。等后面有时间的话,我还是想按照X509 V3 标准,自己创建RawData,然后生成证书,这样应该是比较灵活的做法。不知道网友们有没有什么更好的方法来创建一个自定义的证书。

 

通过 makecert.exe 创建X509证书的代码如下,供大家参考

 

static object semObj = new object();

 

/// <summary>

/// 自定义的证书信息

/// </summary>

public class T_CertInfo

{

    public String FriendlyName;

    public String Subject;

    public DateTime BeginDate;

    public DateTime EndDate;

    public int SerialNumber;

}

 

/// <summary>

/// 生成X509证书

/// </summary>

/// <param name="makecrtPath">makecert进程的目录</param>

/// <param name="crtPath">证书文件临时目录</param>

/// <param name="certInfo">证书信息</param>

/// <returns></returns>

public static X509Certificate2 CreateCertificate(String makecrtPath, String crtPath,

    T_CertInfo certInfo)

{

    Debug.Assert(certInfo != null);

    Debug.Assert(certInfo.Subject != null);

 

    string MakeCert = makecrtPath + "makecert.exe";

    string fileName = crtPath + "cer";

 

    string userName = Guid.NewGuid().ToString();

 

    StringBuilder arguments = new StringBuilder();

 

    arguments.AppendFormat("-r -n \"{0}\" -ss my -sr currentuser -sky exchange ",

        certInfo.Subject);

 

    if (certInfo.SerialNumber > 0)

    {

        arguments.AppendFormat("-# {0} ", certInfo.SerialNumber);

    }

 

    arguments.AppendFormat("-b {0} ", certInfo.BeginDate.ToString(@"MM\/dd\/yyyy"));

    arguments.AppendFormat("-e {0} ", certInfo.EndDate.ToString(@"MM\/dd\/yyyy"));

    arguments.AppendFormat("\"{0}\"", fileName);

 

    lock (semObj)

    {

        Process p = Process.Start(MakeCert, arguments.ToString());

        p.WaitForExit();

 

        byte[] certBytes = ReadFile(fileName);

        X509Certificate2 cert = new X509Certificate2(certBytes);

        cert = new X509Certificate2(certBytes);

 

        if (certInfo.FriendlyName != null)

        {

            cert.FriendlyName = certInfo.FriendlyName;

        }

 

        return cert;

    }

}

 

 

internal static byte[] ReadFile(string fileName)

{

    using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read))

    {

        int size = (int)f.Length;

        byte[] data = new byte[size];

        size = f.Read(data, 0, size);

        return data;

    }

}

 

获取证书私钥

通过上述方法得到的X509证书,只能获取其公钥信息,由于公钥私钥是成对出现的,如果我们要在程序中使用该证书来加解密,就必须要获取公钥对应的那个私钥。一样是在互联网上没有找到很好的解决办法,只能自己研究。目前总结出两种方法,给大家分享:

第一种方法:

从密钥容器中获取私钥。具体方法如下:

首先在 makecert 的参数中要加入一条 -sk keyname  指定主题的密钥容器位置,该位置包含私钥。如果密钥容器不存在,系统将创建一个。

然后 在执行完 p.WaitForExit(); 这一句后执行下面语句获取私钥和私钥参数

RSAParameters privateKey;

RSACryptoServiceProvider rsa = GetKeyFromContainer("keyname");

privateKey = rsa.ExportParameters(true);

 

public static RSACryptoServiceProvider GetKeyFromContainer(string ContainerName)

{

    // Create the CspParameters object and set the key container

    // name used to store the RSA key pair.

    CspParameters cp = new CspParameters();

    cp.KeyContainerName = ContainerName;

 

    // Create a new instance of RSACryptoServiceProvider that accesses

    // the key container MyKeyContainerName.

    return new RSACryptoServiceProvider(cp);

}

 

这种方法有一个缺点就是程序的调用者必须要具备读取密钥容器的权限才行,如果是Web应用,由于IIS来宾帐户没有这个权限,将无法读取密钥容器中的密钥。尝试采用模拟超级用户登录的方法(NetworkSecurity.ImpersonateUser),也无法解决这个问题,而且这样做我个人觉得对网站的安全性方面也不是很好。后来想出了第二种方法,就是干脆重置密钥对,用自己生成的密钥对替换证书中的密钥对,试了一下,还是行之有效的。

第二种方法:

重置密钥对,方法如下:

首先要生成一个加密算法和加密位数与makecert生成的证书密钥相同的密钥。通过实测发现makecert采用交换密钥时,默认产生一个1024位RSA密钥,Exponent 为1,0,1,这和

RSACryptoServiceProvider 默认的密钥是相同的。所以只要用 RSACryptoServiceProvider RSA = new RSACryptoServiceProvider() 生成一个密钥就可以了。

 

第二步就是替换,也就是将密钥文件中公钥参数替换为要置换的公钥参数。

 

RSAParameters publicKey;

RSAParameters privateKey;

 

RSACryptoServiceProvider RSA = (RSACryptoServiceProvider)cert.PublicKey.Key;

publicKey = RSA.ExportParameters(false);

 

//查找公钥参数在RawData中的位置

if (publicKey.Modulus.Length != 128 || publicKey.Exponent.Length != 3)

{

    throw new Exception("public key module lenght != 128!");

}

 

if (publicKey.Exponent[0] != 1 ||

    publicKey.Exponent[1] != 0 ||

    publicKey.Exponent[2] != 1)

{

    throw new Exception("public key Exponent != 101!");

}

 

byte[] module = publicKey.Modulus;

 

int i = 0;

int matchCnt = 0;

int modulePos = 0;

int j = 0;

 

while (i < certBytes.Length)

{

 

    if (certBytes[i] == module[j]) //cerBytes 为 RawData,什么可以参加创建证书的代码

    {

        i++;

        j++;

        matchCnt++;

 

        if (matchCnt == 128)

        {

            modulePos = i - 128;

            break;

        }

    }

    else

    {

        if (matchCnt == 128)

        {

            modulePos = i - 128;

            break;

        }

        else

        {

            matchCnt = 0;

            j = 0;

            i++;

        }

    }

}

 

//创建密钥对

RSA = new RSACryptoServiceProvider();

publicKey = RSA.ExportParameters(false);

privateKey = RSA.ExportParameters(true);

 

//将要重置的密钥对中的公钥参数覆盖原参数

 

j = 0;

for (i = modulePos; i < modulePos + 128; i++)

{

    certBytes[i] = publicKey.Modulus[j];

    j++;

}

 

//用新参数重新创建证书

cert = new X509Certificate2(certBytes);

 

这样一来privateKey就成了新证书的私钥了。

 

这种方法的问题:

这种方法的问题是查找证书中公钥信息,是通过匹配的方式来做的,这是一个偷懒的方法,正确的做法应该是按照标准的定义来查找,由于暂时没有太多时间去仔细研究标准,所以就偷了一个懒,但感觉这种方法目前来说还是行之有效的,待以后改进吧。

 

 

参考资料

http://www.ietf.org/rfc/rfc2459.txt IETF X509 V3 版本标准全文

http://blog.csdn.net/chinaipcnet/archive/2007/05/23/1621989.aspx makecert.exe使用说明

 from :http://www.cnblogs.com/eaglet/archive/2007/07/11/814600.html

转载于:https://www.cnblogs.com/gxh973121/archive/2007/07/12/815117.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/277028.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css样式优先级计算规则

css样式的优先级分为引入优先级和声明优先级。 引入优先级 引入样式一般分为外部样式&#xff0c;内部样式&#xff0c;内联样式。 外部样式&#xff1a;使用link引入的外部css文件。 内部样式&#xff1a;使用style标签书写的css样式。 内联样式&#xff1a;直接书写在html标签…

phpstudy-5.6.27-nts  安装redis扩展

2019独角兽企业重金招聘Python工程师标准>>> redis扩展安装流程 第一步&#xff1a; 首先直接查看一下phpinfo()的信息 找到下面两条信息 Architecturex86PHP Extension BuildAPI20131226,NTS,VC11Loaded Configuration FileD:\phpStudy\php\php-5.6.27-nts\php.ini…

用DDA Convolution和Perlin Noise来模拟水粉画笔触

在西方&#xff0c;水彩画和水粉画是可以统称为Watercolor的,水粉画通常也称为不透明水彩画或树胶水彩画&#xff08;Gouache&#xff09;&#xff0c;两者既有相似之处&#xff0c;又有所区别。水粉画是以水作为媒介&#xff0c;这一点&#xff0c;它与水彩画是相同的。所以&a…

第三课 Makefile文件的制作(上)

1.序言&#xff1a; 前面的课程讲解了从gcc编译过程到其实践&#xff0c;大家可以看到其实在这些步骤中有些是可以简化编译的&#xff0c;但由于参数多以及项目中文件数量多的原因难免会造成错误甚至是浪费大量的时间在这编译上&#xff0c;为此linux系统中专门也有这个工具&am…

刺猬文│从启动方式来看播客链的运行机制—设置验证者

&#xff08;图片出自网络&#xff0c;版权归原作者所有&#xff09;上一篇刺猬文我们介绍了播客链是如何实现Dpos的&#xff0c;其实质过程就是&#xff1a;节点A打包&#xff0c;将打包的区块发送给其它的节点&#xff0c;其它节点根据当前时间&#xff0c;判断是否应该由A节…

[记忆碎片的磁盘整理]老妈

卷标&#xff1a;老妈 挂载点&#xff1a;/family/mother 分区格式&#xff1a;亲情 备注&#xff1a;老妈固然是我人生中的至亲&#xff0c;但是搜遍我的大闹&#xff0c;也没能发现一点关于老妈的特殊记忆。老妈是一位再普通不过的女人、妻子、母亲。也本该如此吧。碎片文件&…

探究Java如何实现原子操作(atomic operation)

1. 让我们首先了解下java 中 Volatile 关键字 Volatile可实现java内存模型当中的可见性&#xff0c; java内存模型的可见性&#xff1a; 可见性&#xff0c;是指线程之间的可见性&#xff0c;一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果&#xff0c;另一…

JAVA-重写equalse规范、技巧

JAVA-重写equalse规范、技巧 1、自反性 任何非空引用x&#xff0c;x.equalse(x) 应该返回true2、对称性 任何引用x和y&#xff0c;当x.equals(y)返回true&#xff0c;y.equals(x)也应返回true3、传递性 任何引用x、y和z&#xff0c;当x.equalse(y)和y.equalse(z)&#xff0c;那…

Password Creator(HTA)

<!--- 功能&#xff1a; 生成随机密码- 输入&#xff1a; 用户的设置- 输出&#xff1a; 随机密码&#xff0c;同时拷贝到剪切板- 作者&#xff1a; maskx- 版本&#xff1a; v1.0- 历史纪录&#xff1a; 2007-7-11新建 - 创建时间&#xff1a; 200…

Julia 排坑指南

Julia 是一个高效的计算语言&#xff0c;据说性能和C有一拼。 Google也开始支持TPU的Julia&#xff0c; 个人觉得他的可视化比较厉害&#xff0c;下面是自己安装过程的截图&#xff0c;由于Julia的服务器在国外&#xff0c;所以下载的过程会出现一些不可描述的问题&#xff0c;…

Arts 第十九周(7/22 ~ 7/28)

ARTS是什么&#xff1f;Algorithm&#xff1a;每周至少做一个leetcode的算法题&#xff1b;Review&#xff1a;阅读并点评至少一篇英文技术文章&#xff1b;Tip&#xff1a;学习至少一个技术技巧&#xff1b;Share&#xff1a;分享一篇有观点和思考的技术文章。 Algorithm 深度…

难过的要命。。。。。。

请允许我这样叫几下&#xff0c;我知道自己是个老姑娘了&#xff0c;不能像小女孩那样碰到点不开心的事就一哭二闹三上吊。我不哭不闹更不会傻得去上吊&#xff0c;我还有几十年的大好日子要过呢&#xff0c;我儿子还没生呢。现在我们还没有正式的摊牌&#xff0c;应该说只差最…

基于.NET2.0的System.Net.Mail发送邮件Demo

第一种: //emailaddress邮件接收者地址 //mailcontent邮件主体内容 //mailtitle邮件标题 //mailsubject邮件主题 public bool SendMail(string emailaddress,string mailcontent,string mailtitle,string mailsubject) { …

美国美国,USA USA

外派美国微软接的项目职位名称&#xff1a;开发主管&#xff08;SDE LEADER&#xff09; 工作城市&#xff1a;Redmond 职位要求: Good English communicationGood SQL and C# .net framework experienceBackend developmentBI knowledge (he is expected to deal with millio…

Windows Server 2016之RDS配置证书

证书我们可以自己创建也可以到阿里云申请&#xff0c;一次申请可以用一年&#xff0c;&#xff08;自己创建的证书是不受信任的&#xff09;所以我们在阿里云上申请的&#xff0c;下面我们就把申请到的证书下载下来&#xff0c;放到一个文件夹里&#xff0c;并解压接下来我们就…

升级tomcat7.0之后的问题

学习web也有几天了&#xff0c;今天把tomcat改成7.0的之后老是出现严重警告&#xff1a; 严重: The web application [/struts2_0100] created a ThreadLocal with key of type [com.opensymphony.xwork2.inject.ContainerImpl$10](value[com.opensymphony.xwork2.inject.Conta…

慎重对待青霉素皮试

青霉素类药不同品种间存在交叉过敏关系。 所以&#xff0c;中国药典规定&#xff0c;青霉素类药物在注射前必先使用青霉素钠&#xff08;钾&#xff09;及氯化钠注射液配制的溶液做皮内敏感试验。皮试液浓度为每毫升500单位&#xff0c; 皮内注射0.1毫升&#xff0c;阳性反应者…

2018阿里云双11拼团大促主会场全攻略

为什么80%的码农都做不了架构师&#xff1f;>>> 摘要&#xff1a; 在双十一这个一年唯一一次的大幅度降价促销日&#xff0c;怎样才能花最少的钱配置最特惠的云服务&#xff1f;云栖社区特为各位开发者奉献出省钱大法如下&#xff01; 2018阿里云双十一拼团大促活动…

匿名用户访问用发布站点模板创建网站的列表项时要求登录的问题解决

因为发布站点中的一个Feature被打开了&#xff0c;造成将列表FormPage的查看给Lock了&#xff0c;所以需要登录&#xff0c;将其关闭就OK了。哈哈。英文KB&#xff1a;Users are unexpectedly prompted to enter their credentials when they access a list in a Windows Share…

知识点1: 进度条随数据变化,并添加渐变样式

效果图&#xff1a; dom&#xff1a; //  进度条             <div class"progress" :style"styleObj1"><div class"point"></div></div>//  数据容器<div class"precent"><counte…