如何创建证书请求



   X509证书实质是公钥和与之相关的拥有者和签发者的一个打包。因此,为了创建一个证书请求,必须先产生一个公私密钥对。 X.509 证书在 openssl 中是用 X509_REQ 对象表示的。证书请求中主要包括密钥对中的公钥部分,除此之外还包括 subjectName 字段和其他一些 X.509 的属性。这些属性对于证书请求来说是可选参数,但是 subject name 却是必须有的。


  X509_NAME对象类型代表证书的名称。具体说来证书请求只包含 subject name ,但是完整的证书包含 subject issuer name 。设置名称字段目的是为了完整地标识一个实体 -- 一台服务器,某个人,或者一家公司等等。对于这些实体,名称字段包括多个条目比如 country name organization name common name 等。

    理论上在名称中可以包含任意的字段,但实际上有一些标准规定。在oenssl 内部通过一个整数来标识字段,也就是 NID


    如前所述,证书名称是由X509_NAME对象表示的。该对象实质是X509_NAME_ENTRY对象的集合。每一个 X509_NAME_ENTRY对象代表了名称中一个字段及其相应的内容值。因此,需要为每一个字段创建 X509_NAME_ENTRY 对象,然后将之放入证书请求的名称字段中。首选查找需要创建的字段的NID ,通过 NID 创建 X509_NAME_ENTRY 对象并添加数据,然后将该字段条目加入 X509_NAME 中,如此重复直到组装好名称字段后,就可以添加到 X509_REQ 对象中。



X509 V3扩展项


    SSL中非常有用的一个扩展是 subjectAltName 。该扩展包含一个 dNSName 的字段,这个字段包含了终端实体处理证书需要的 FQDN 。在发送证书请求给 CA 制作证书之前,有必要先添加扩展项。

    X509_EXTENSION类型对象代表了 X509 对象内部的单项扩展条目。添加扩展的过程简言之是把所有要求的扩展项添加到 STACK_OF(X509_EXTENSION) 对象中,再将该 STACK 加入到证书请求中即可。

    回顾一下创建证书请求:首先创建X509_REQ 对象,为之添加一个 subject name 和公钥,添加所有需要的扩展项,最后使用私钥对请求进行签名。为了表示公钥和私钥组成部分,这里使用通用EVP_KEY类型以及相应的函数。Openssl中消息摘要算法是通过 EVP_MD 对象表示的。基于要签发 key 的类型--RSA或者DSA ,我们需要制定不同的 EVP_MD 对象。但是在签名时候并不知道公钥算法,因此必须使用抽象 EVP_PKEY 接口。可以通过探究 EVP_PKEY 对象内部知道其算法。。。。( 这一段不甚明了。)

 

 


 

Example 10-5. A program to generate a certificate request #include #include #include #include #include #include void handle_error(const char *file, int lineno, const char *msg) { fprintf(stderr, "** %s:%i %s/n", file, lineno, msg); ERR_print_errors_fp(stderr); exit(-1); } #define int_error(msg) handle_error(__FILE__, __LINE_ _, msg) #define PKEY_FILE "privkey.pem" #define REQ_FILE "newreq.pem" #define ENTRY_COUNT 6 struct entry { char *key; char *value; }; struct entry entries[ENTRY_COUNT] = { { "countryName", "US" }, { "stateOrProvinceName", "VA" }, { "localityName", "Fairfax" }, { "organizationName", "Zork.org" }, { "organizationalUnitName", "Server Division" }, { "commonName", "Server 36, Engineering" }, }; int main(int argc, char *argv[]) { int i; X509_REQ *req; X509_NAME *subj; EVP_PKEY *pkey; EVP_MD *digest; FILE *fp; OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); seed_prng(); /* first read in the private key */ if (!(fp = fopen(PKEY_FILE, "r"))) int_error("Error reading private key file"); if (!(pkey = PEM_read_PrivateKey(fp, NULL, NULL, "secret"))) int_error("Error reading private key in file"); fclose(fp); /* create a new request and add the key to it */ if (!(req = X509_REQ_new())) int_error("Failed to create X509_REQ object"); X509_REQ_set_pubkey(req, pkey); /* assign the subject name */ if (!(subj = X509_NAME_new())) int_error("Failed to create X509_NAME object"); for (i = 0; i < ENTRY_COUNT; i++) { int nid; X509_NAME_ENTRY *ent; if ((nid = OBJ_txt2nid(entries[i].key)) == NID_undef) { fprintf(stderr, "Error finding NID for %s/n", entries[i].key); int_error("Error on lookup"); } if (!(ent = X509_NAME_ENTRY_create_by_NID(NULL, nid, MBSTRING_ASC, entries[i].value, - 1))) int_error("Error creating Name entry from NID"); if (X509_NAME_add_entry(subj, ent, -1, 0) != 1) int_error("Error adding entry to Name"); } if (X509_REQ_set_subject_name(req, subj) != 1) int_error("Error adding subject to request"); /* add an extension for the FQDN we wish to have */ { X509_EXTENSION *ext; STACK_OF(X509_EXTENSION) *extlist; char *name = "subjectAltName"; char *value = "DNS:splat.zork.org"; extlist = sk_X509_EXTENSION_new_null(); if (!(ext = X509V3_EXT_conf(NULL, NULL, name, value))) int_error("Error creating subjectAltName extension"); sk_X509_EXTENSION_push(extlist, ext); if (!X509_REQ_add_extensions(req, extlist)) int_error("Error adding subjectAltName to the request"); sk_X509_EXTENSION_pop_free(extlist, X509_EXTENSION_free); } /* pick the correct digest and sign the request */ if (EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) digest = EVP_dss1(); else if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) digest = EVP_sha1(); else int_error("Error checking public key for a valid digest"); if (!(X509_REQ_sign(req, pkey, digest))) int_error("Error signing request"); /* write the completed request */ if (!(fp = fopen(REQ_FILE, "w"))) int_error("Error writing to request file"); if (PEM_write_X509_REQ(fp, req) != 1) int_error("Error while writing request"); fclose(fp); EVP_PKEY_free(pkey); X509_REQ_free(req); return 0; }  


使用合适的PEM调用来读取私钥。公钥是私钥中信息的一个子集(  a public key is a subset of  the information in a private key )。

你可能感兴趣的:(OpenSSL)