openssl 生成CSR

39 篇文章 0 订阅

将openssl如何生成CSR写了一上DEMO,支持扩展属性,同时增加了通过DN字符串转X509_NAME的方法。

#include <string.h>
#include <openssl/x509.h>
#include <openssl/rsa.h>
#pragma comment(lib, "libeay32.lib")

/*
* subject is expected to be in the format /type0=value0/type1=value1/type2=...
* where characters may be escaped by \
*/
X509_NAME *parse_name(char *subject, long chtype, int multirdn)
{
	size_t buflen = strlen(subject)+1; /* to copy the types and values into. due to escaping, the copy can only become shorter */
	char *buf = OPENSSL_malloc(buflen);
	size_t max_ne = buflen / 2 + 1; /* maximum number of name elements */
	char **ne_types = OPENSSL_malloc(max_ne * sizeof (char *));
	char **ne_values = OPENSSL_malloc(max_ne * sizeof (char *));
	int *mval = OPENSSL_malloc (max_ne * sizeof (int));
	
	char *sp = subject, *bp = buf;
	int i, ne_num = 0;
	
	X509_NAME *n = NULL;
	int nid;
	
	if (!buf || !ne_types || !ne_values || !mval)
	{
		//BIO_printf(bio_err, "malloc error\n");
		goto error;
	}	
	
	if (*subject != '/')
	{
		//BIO_printf(bio_err, "Subject does not start with '/'.\n");
		goto error;
	}
	sp++; /* skip leading / */
	
	/* no multivalued RDN by default */
	mval[ne_num] = 0;
	
	while (*sp)
	{
		/* collect type */
		ne_types[ne_num] = bp;
		while (*sp)
		{
			if (*sp == '\\') /* is there anything to escape in the type...? */
			{
				if (*++sp)
					*bp++ = *sp++;
				else	
				{
					//BIO_printf(bio_err, "escape character at end of string\n");
					goto error;
				}
			}	
			else if (*sp == '=')
			{
				sp++;
				*bp++ = '\0';
				break;
			}
			else
				*bp++ = *sp++;
		}
		if (!*sp)
		{
			//BIO_printf(bio_err, "end of string encountered while processing type of subject name element #%d\n", ne_num);
			goto error;
		}
		ne_values[ne_num] = bp;
		while (*sp)
		{
			if (*sp == '\\')
			{
				if (*++sp)
					*bp++ = *sp++;
				else
				{
					//BIO_printf(bio_err, "escape character at end of string\n");
					goto error;
				}
			}
			else if (*sp == '/')
			{
				sp++;
				/* no multivalued RDN by default */
				mval[ne_num+1] = 0;
				break;
			}
			else if (*sp == '+' && multirdn)
			{
				/* a not escaped + signals a mutlivalued RDN */
				sp++;
				mval[ne_num+1] = -1;
				break;
			}
			else
				*bp++ = *sp++;
		}
		*bp++ = '\0';
		ne_num++;
	}	
	
	if (!(n = X509_NAME_new()))
		goto error;
	
	for (i = 0; i < ne_num; i++)
	{
		if ((nid=OBJ_txt2nid(ne_types[i])) == NID_undef)
		{
			//BIO_printf(bio_err, "Subject Attribute %s has no known NID, skipped\n", ne_types[i]);
			continue;
		}
		
		if (!*ne_values[i])
		{
			//BIO_printf(bio_err, "No value provided for Subject Attribute %s, skipped\n", ne_types[i]);
			continue;
		}
		
		if (!X509_NAME_add_entry_by_NID(n, nid, chtype, (unsigned char*)ne_values[i], -1,-1,mval[i]))
			goto error;
	}
	
	OPENSSL_free(ne_values);
	OPENSSL_free(ne_types);
	OPENSSL_free(buf);
	OPENSSL_free(mval);
	return n;
	
error:
	X509_NAME_free(n);
	if (ne_values)
		OPENSSL_free(ne_values);
	if (ne_types)
		OPENSSL_free(ne_types);
	if (mval)
		OPENSSL_free(mval);
	if (buf)
		OPENSSL_free(buf);
	return NULL;
}

X509_NAME *CreateDN(char *pbEmail, char *pbCN, char *pbOU, char *pbO, char *pbL, char *pbST, char *pbC)
{
	X509_NAME *pX509Name = NULL;
	if(pbCN == NULL)
	{
		return NULL;
	}
	
	if (!(pX509Name = X509_NAME_new()))
	{
		return NULL;
	}
	X509_NAME_add_entry_by_txt(pX509Name, "emailAddress", V_ASN1_UTF8STRING, pbEmail, -1, -1, 0);
	X509_NAME_add_entry_by_txt(pX509Name, "CN", V_ASN1_UTF8STRING, pbCN, -1, -1, 0);
	X509_NAME_add_entry_by_txt(pX509Name, "OU", V_ASN1_UTF8STRING, pbOU, -1, -1, 0);
	X509_NAME_add_entry_by_txt(pX509Name, "O", V_ASN1_UTF8STRING, pbO, -1, -1, 0);
	X509_NAME_add_entry_by_txt(pX509Name, "L", V_ASN1_UTF8STRING, pbL, -1, -1, 0);
	X509_NAME_add_entry_by_txt(pX509Name, "ST", V_ASN1_UTF8STRING, pbST, -1, -1, 0);
	X509_NAME_add_entry_by_txt(pX509Name, "C", V_ASN1_UTF8STRING, pbC, -1, -1, 0);
	return pX509Name;
}

int	GenCSR(char *pbDN, int nDNLen, char *pCSR, size_t nCSRSize)
{
	char szAltName[] = "DNS:www.jinhill.com";
	char szComment[] = "Create by Jinhill";
	char szKeyUsage[] = "digitalSignature, nonRepudiation";
	char szExKeyUsage[] = "serverAuth, clientAuth";
	
	X509_REQ		*pX509Req = NULL;
	int				iRV = 0;
	long			lVer = 3;
	X509_NAME		*pX509DN = NULL;
	EVP_PKEY		*pEVPKey = NULL;
	RSA				*pRSA = NULL;
	X509_NAME_ENTRY	*pX509Entry = NULL;
	char			szBuf[255] = {0};
	char			mdout[20];
	int				nLen, nModLen;
	int				bits = 2048;
	unsigned long	E = RSA_3;
	unsigned char	*pDer = NULL;
	unsigned char	*p = NULL;
	FILE			*fp = NULL;
	const EVP_MD	*md = NULL;
	X509			*pX509 = NULL;
	BIO				*pBIO = NULL;
	BIO				*pPemBIO = NULL;
	BUF_MEM			*pBMem = NULL;
	
	//STACK_OF(X509_EXTENSION) *pX509Ext;
	
	if(pbDN == NULL)
	{
		return -1;
	}
	pX509DN = parse_name(pbDN, V_ASN1_UTF8STRING, 0);
	
	pX509Req = X509_REQ_new();
	
	iRV = X509_REQ_set_version(pX509Req, lVer);
	
	// subject pX509Name 
	iRV = X509_REQ_set_subject_name(pX509Req, pX509DN);
	
	/* pub key */
	pEVPKey = EVP_PKEY_new();
	pRSA = RSA_generate_key(bits, E, NULL, NULL);
	EVP_PKEY_assign_RSA(pEVPKey, pRSA);
	iRV = X509_REQ_set_pubkey(pX509Req, pEVPKey);
	
	/* attribute */
	strcpy(szBuf, szAltName);
	nLen = strlen(szBuf);
	iRV = X509_REQ_add1_attr_by_txt(pX509Req, "subjectAltName", V_ASN1_UTF8STRING, szBuf, nLen);
	
	strcpy(szBuf, szKeyUsage);
	nLen = strlen(szBuf);
	iRV = X509_REQ_add1_attr_by_txt(pX509Req, "keyUsage", V_ASN1_UTF8STRING, szBuf, nLen);
	
	
	strcpy(szBuf, szExKeyUsage);
	nLen = strlen(szBuf);
	iRV = X509_REQ_add1_attr_by_txt(pX509Req, "extendedKeyUsage", V_ASN1_UTF8STRING, szBuf, nLen);
	
	
	strcpy(szBuf, szComment);
	nLen = strlen(szBuf);
	iRV = X509_REQ_add1_attr_by_txt(pX509Req, "nsComment", V_ASN1_UTF8STRING, szBuf, nLen);
	
	
	md = EVP_sha1();
	iRV = X509_REQ_digest(pX509Req, md, mdout, &nModLen);
	iRV = X509_REQ_sign(pX509Req, pEVPKey, md);
	if(!iRV)
	{
		printf("sign err!\n");
		X509_REQ_free(pX509Req);
		return -1;
	}
	
	// 写入文件PEM格式 
	// 	pBIO = BIO_new_file("certreq.txt", "w");
	// 	PEM_write_bio_X509_REQ(pBIO, pX509Req, NULL, NULL);
	// 	BIO_free(pBIO);
	
	//返回PEM字符
	pPemBIO = BIO_new(BIO_s_mem());
	PEM_write_bio_X509_REQ(pPemBIO, pX509Req, NULL, NULL);
	BIO_get_mem_ptr(pPemBIO,&pBMem);
	if(pBMem->length <= nCSRSize)
	{
		memcpy(pCSR, pBMem->data, pBMem->length);
	}
	BIO_free(pPemBIO);
	
	/* DER编码 */
	//nLen = i2d_X509_REQ(pX509Req, NULL);
	//pDer = (unsigned char *)malloc(nLen);
	//p = pDer;
	//nLen = i2d_X509_REQ(pX509Req, &p);
	//free(pDer);
	
	//	验证CSR
	OpenSSL_add_all_algorithms();
	iRV = X509_REQ_verify(pX509Req, pEVPKey);
	if(iRV<0)
	{
		printf("verify err.\n");
	}
	
	X509_REQ_free(pX509Req);
	return nCSRSize;
}


int	main()
{
	char chDN[255] = "/CN=www.jinhill.com/O=Beijing Jinhill Inc./C=CN";
	char chCSR[2048] = {0};
	int rv = GenCSR(chDN, strlen(chDN), chCSR, sizeof(chCSR));
	printf("CSR:\n%s", chCSR);
}


  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在 C 语言中使用 OpenSSL生成 CSR,可以按照以下步骤: 1. 包含 OpenSSL 库头文件和链接库: ```c #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h> #pragma comment(lib, "libeay32.lib") #pragma comment(lib, "ssleay32.lib") ``` 2. 生成 RSA 密钥对: ```c RSA *rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL); ``` 这将生成一个 2048 位的 RSA 密钥对。 3. 创建 X509_REQ 对象: ```c X509_REQ *req = X509_REQ_new(); ``` 4. 设置 CSR 的主题信息: ```c X509_NAME *name = X509_REQ_get_subject_name(req); X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "example.com", -1, -1, 0); ``` 这里将 "CN" 设置为 "example.com",可以根据需要修改。 5. 将公钥添加到 CSR 中: ```c X509_REQ_set_pubkey(req, rsa); ``` 6. 签名 CSR: ```c X509_REQ_sign(req, rsa, EVP_sha256()); ``` 7. 将 CSR 写入文件: ```c FILE *fp = fopen("example.csr", "wb"); if (fp) { PEM_write_X509_REQ(fp, req); fclose(fp); } ``` 完整的示例代码可以参考以下代码: ```c #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h> #pragma comment(lib, "libeay32.lib") #pragma comment(lib, "ssleay32.lib") int main(void) { RSA *rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL); X509_REQ *req = X509_REQ_new(); X509_NAME *name = X509_REQ_get_subject_name(req); X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "example.com", -1, -1, 0); X509_REQ_set_pubkey(req, rsa); X509_REQ_sign(req, rsa, EVP_sha256()); FILE *fp = fopen("example.csr", "wb"); if (fp) { PEM_write_X509_REQ(fp, req); fclose(fp); } X509_REQ_free(req); RSA_free(rsa); return 0; } ``` 这将生成一个名为 "example.csr" 的 CSR 文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值