创建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

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

  1. php获取x509证书信息,创建X509证书,并获取证书密钥的一点研究

    作者:肖波 背景 服务器SSL数字证书和客户端单位数字证书的格式遵循X.509标准.X.509是由国际电信联盟(ITU-T)制定的数字证书标准.为了提供公用网络用户目录信息服务,ITU于1988年制定 ...

  2. IOS APP获取证书、打包、发布蒲公英详解

    需注意的是第6步的选择.获取证书做到附加项之前就可以了. 获取证书:获取证书方式 -------------------------------------------------- 打包时要注意的是 ...

  3. java p12 ssl_java读取双向证书(p12)证书向微信发送请求

    对有些微信接口为保证安全,需要p12证书进行请求, 获取证书: 获取证书的方式.png PHP用到的证书.png 证书使用说明.png 加载证书的相关请求方式代码: private static Re ...

  4. Java中的微信支付(2):API V3 微信平台证书的获取与刷新

    1. 前言 在Java 中的微信支付(1):API V3 版本签名详解一文中胖哥讲解了微信支付 V3 版本 API 的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API 证书对参数 ...

  5. ansible 建 kubernetes 证书签名请求_Java中的微信支付(2):API V3 微信平台证书的获取与刷新...

    1. 前言 在Java 中的微信支付(1):API V3 版本签名详解一文中胖哥讲解了微信支付 V3 版本 API 的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API 证书对参数 ...

  6. java读取微信证书_Java中的微信支付(2):API V3 微信平台证书的获取与刷新

    1. 前言 在Java中的微信支付(1):API V3版本签名详解一文中胖哥讲解了微信支付V3版本API的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API证书对参数进行加签,微信 ...

  7. aes加密 java_Java中的微信支付(2):API V3 微信平台证书的获取与刷新

    1. 前言 在Java 中的微信支付(1):API V3 版本签名详解一文中胖哥讲解了微信支付 V3 版本 API 的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API 证书对参数 ...

  8. Linux创建新用户并使用证书远程登录

    因业务需要,需要在服务器上创建多用户,方便多人维护,那么可以利用证书登录创建多用户登录,然后用户如果需要root权限再手动切换即可,下面简单介绍下在Linux上如何进行多用户创建以及使用证书登录. 添 ...

  9. 自建ca根证书_如何创建私有 CA 并签发证书

    为什么需要自己的 CA? 因为公共 CA (比如排名前几的这几家:Comodo, Symantec, GlobalSign, DigiCert, StartCom)颁发证书要收费,而且价格很贵.当然现 ...

最新文章

  1. Android 白天/夜间模式切换
  2. ubuntu系统安装mysql二进制压缩包(tar.gz)以及navicat远程连接服务器(linux系统)
  3. Java2WSDL 和 WSDL2Java(Axis)
  4. hdu 1879 继续畅通工程 最小生成树
  5. 尚洋优选健康美电商平台启动仪式在广州召开
  6. Abp v2.8.0发布 路线图
  7. python3.6字典有序_为什么从Python 3.6开始字典有序并效率更高
  8. 白岩松曾说过这样一段话
  9. 判断IP是否为搜索引擎蜘蛛或爬虫
  10. 麻省理工18年春软件构造课程阅读06“规格说明”
  11. SPSS主成分分析(PCA)
  12. 一个基于QT的开源串口调试工具
  13. ubnt路由器虚拟服务器,UBNT UAP系列 Wi-Fi设置教程 装修必看
  14. librdkafka配置
  15. android闹铃唤醒软件,温柔唤醒闹钟app_温柔的闹钟铃声有哪些_华为智能闹钟智能唤醒-多特软件站安卓网...
  16. mac登陆远程服务器
  17. EasyExcel 导出 excel(二)添加序号列,设置excel打印样式,导出即可打印
  18. 机器学习之深度学习入门
  19. 计算机视觉工程师收入高吗?月薪有多少?
  20. 【Spring】IOC理论推导、IOC本质

热门文章

  1. Linux命令行编辑快捷键
  2. Maven for Eclipse 第二章 ——安装 m2eclipse插件
  3. JavaScript复制数组
  4. MySQL入门-3:安装与客户端工具
  5. WPF--ComboBox数据绑定
  6. 《CLR via C#》读书笔记 之 参数
  7. Halcon: 畸变矫正与标定(1)
  8. C++总结笔记(八)—— 菱形继承
  9. oracle在线sql数据库设计,一款在线ER模型设计工具,支持MySQL、SQLServer、Oracle、Postgresql...
  10. 期刊论文格式模板 电子版_期刊论文的框架结构