以编程方式使用OpenSSL创buildX509证书
我有一个C / C ++应用程序,我需要创build一个同时包含公钥和私钥的X509证书。 证书可以自签名,也可以不签名,不重要。
我想要在应用程序内部执行此操作,而不是从命令行执行。
什么OpenSSL的function会为我做这个? 任何示例代码是一个奖金!
您需要首先熟悉术语和机制。
根据定义,X.509 证书不包含私钥。 相反,它是公钥的CA签名版本(以及CA放入签名的任何属性)。 PEM格式实际上只支持密钥和证书的单独存储 – 尽pipe可以将两者连接起来。
在任何情况下,您都需要调用20多个OpenSSL API的不同函数来创build密钥和自签名证书。 一个例子是在OpenSSL源代码本身,在demos / x509 / mkcert.c中
有关更详细的答案,请参阅下面的Nathan Osman的解释 。
我意识到这是一个很晚(很长)的答案。 但考虑到这个问题似乎排在search引擎的结果,我认为这可能是值得写一个体面的答案。
下面的许多内容都是从这个演示和OpenSSL文档中借用的。 下面的代码适用于C和C ++。
在我们实际创build证书之前,我们需要创build一个私钥。 OpenSSL提供了EVP_PKEY
结构,用于在内存中存储与algorithm无关的私钥。 这个结构在openssl/evp.h
声明,但是被openssl/evp.h
包含(我们稍后需要),所以你不需要明确地包含头部。
为了分配一个EVP_PKEY
结构,我们使用EVP_PKEY_new
:
EVP_PKEY * pkey; pkey = EVP_PKEY_new();
还有一个释放结构的对应函数 – EVP_PKEY_free
– 接受一个参数:上面初始化的EVP_PKEY
结构。
现在我们需要生成一个密钥。 对于我们的例子,我们将生成一个RSA密钥。 这是在openssl/rsa.h
声明的RSA_generate_key
函数完成的。 这个函数返回一个指向RSA
结构的指针。
函数的简单调用可能如下所示:
RSA * rsa; rsa = RSA_generate_key( 2048, /* number of bits for the key - 2048 is a sensible value */ RSA_F4, /* exponent - RSA_F4 is defined as 0x10001L */ NULL, /* callback - can be NULL if we aren't displaying progress */ NULL /* callback argument - not needed in this case */ );
如果RSA_generate_key
的返回值为NULL
,则出现错误。 如果没有,那么我们现在有一个RSA密钥,我们可以从之前将它分配给我们的EVP_PKEY
结构:
EVP_PKEY_assign_RSA(pkey, rsa);
当EVP_PKEY
结构被释放时, RSA
结构将被自动释放。
现在为证书本身。
OpenSSL使用X509
结构来表示内存中的x509证书。 这个结构的定义在openssl/x509.h
。 我们需要的第一个函数是X509_new
。 它的使用相对简单:
X509 * x509; x509 = X509_new();
和EVP_PKEY
,有一个释放结构的相应函数 – X509_free
。
现在我们需要使用一些X509_*
函数设置证书的几个属性:
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
这将我们的证书的序列号设置为“1”。 一些开放源代码的HTTP服务器拒绝接受序列号为“0”的证书,这是默认的。 下一步是指定证书实际有效的时间跨度。 我们用以下两个函数调用:
X509_gmtime_adj(X509_get_notBefore(x509), 0); X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
第一行将证书的notBefore
属性设置为当前时间。 ( X509_gmtime_adj
函数将指定的秒数添加到当前时间 – 在这种情况下为无)。第二行将证书的notAfter
属性设置为从现在开始的365天(60秒* 60分钟* 24小时* 365天)。
现在我们需要使用我们之前生成的密钥为我们的证书设置公钥:
X509_set_pubkey(x509, pkey);
由于这是自签证书,我们将发行人的名称设置为主题的名称。 该过程的第一步是获取主题名称:
X509_NAME * name; name = X509_get_subject_name(x509);
如果您曾经在命令行上创build过自签名证书,那么您可能会记得要求input国家代码。 这里是我们提供的组织('O')和公共名称('CN'):
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"CA", -1, -1, 0); X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"MyCompany Inc.", -1, -1, 0); X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"localhost", -1, -1, 0);
(我在这里使用的值是'CA',因为我是加拿大人,这是我们的国家代码。还要注意参数#4需要明确地转换成一个unsigned char *
。)
现在我们可以设置发行人的名字:
X509_set_issuer_name(x509, name);
最后我们准备好执行签名过程。 我们使用前面生成的密钥来调用X509_sign
。 这个代码很简单:
X509_sign(x509, pkey, EVP_sha1());
请注意,我们正在使用SHA-1哈希algorithm来签署密钥。 这不同于我在本答案开头提到的使用MD5的mkcert.c
演示。
我们现在有一个自签名的证书! 但是我们还没有完成 – 我们需要将这些文件写入磁盘。 值得庆幸的是,OpenSSL也在这里介绍了openssl/pem.h
中声明的PEM_*
函数。 我们需要的第一个是用于保存我们的私钥的PEM_write_PrivateKey
。
FILE * f; f = fopen("key.pem", "wb"); PEM_write_PrivateKey( f, /* write the key to the file we've opened */ pkey, /* our key from earlier */ EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */ "replace_me", /* passphrase required for decrypting the key on disk */ 10, /* length of the passphrase string */ NULL, /* callback for requesting a password */ NULL /* data to pass to the callback */ );
如果您不想encryption私钥,那么只需传递NULL
作为上面的第三个和第四个参数。 无论哪种方式,你一定要确保该文件不是世界上可读的。 (对于Unix用户,这意味着chmod 600 key.pem
。)
呼! 现在我们只需要一个function – 我们需要将证书写入磁盘。 我们需要的function是PEM_write_X509
:
FILE * f; f = fopen("cert.pem", "wb"); PEM_write_X509( f, /* write the certificate to the file we've opened */ x509 /* our certificate */ );
我们完成了! 希望这个答案中的信息足以让你粗略地了解一切是如何工作的,尽pipe我们几乎没有涉及到OpenSSL的表面。
对于那些有兴趣看到上面所有代码在真实应用程序中的样子,我已经把Gist(用C ++编写)放在一起,您可以在这里查看。
非常简单的教程来创build数字证书http://publib.boulder.ibm.com/infocenter/rsthelp/v8r0m0/index.jsp?topic=/com.ibm.rational.test.lt.doc/topics/tcreatecertopenssl.html
关于从你的代码执行这些命令我不知道。
通过system
调用从你的应用程序的任何机会吗? 几个很好的理由这样做:
-
许可:调用
openssl
可执行文件可以将其与您的应用程序分离,并可能提供某些优势。 免责声明:就此咨询律师。 -
文档:OpenSSL附带惊人的命令行文档,大大简化了一个潜在的复杂工具。
-
可testing性:您可以从命令行练习OpenSSL,直到您明确了解如何创build您的证书。 有很多select; 希望花费大约一天的时间,直到你得到所有的细节。 之后,将命令合并到您的应用程序是微不足道的。
如果您select使用API,请在www.openssl.org上查看openssl-dev
开发人员的列表。
祝你好运!