C#工程中使用OPENSSL

                      C#C++/CLI的结合

 

建议读者范围:有一定的C#2.0 C或者C++的语言基础,并且对.Net互操作性有一定的了解

源程序下载地址:https://files.cnblogs.com/sleepingwit/Certificate.rar

总述

         OPENSSL是一个开源的广为使用的开源信息安全SDK,然而该SDK的官方版本是用C/C++语言编写的,因此该SDK的程序不能直接在.Net的虚拟机上运行。笔者最近的一个项目需要生成PKCS#12*.pfx)的数字证书,并且要提供PKCS#12证书到X509(*.cer)证书的转换功能.由于.NET的功能不够完善等诸多原因,笔者不能够很好的使用.Net Framework 2.0 来完成上述功能。OPENSSL可以实现笔者需要的功能,但是无法做到与我们的C#程序交互,经过多次试验,笔者最终采用了C#C++/CLI结合的方式来实现上述功能——C#程序生成pfx证书并提供pfxcer证书的转换。

 

C++/CLI

         .Net Framework 2.0中,微软将Manage C++升级为C++/CLI,我们且不关注该改进的优缺点,在这里我们只关心我们需要的功能。C++/CLI之所以能够满足我们的需要,是因为他提供了一个很好的源代码级的.Net与本机代码的互操作功能。.Net与本机互操作可以有三种方式[2]

         1)基于P/InvokeDLL互操作;

         2COM互操作;

         3 C++ Interop.

第三种C++ InteropC++/CLI独有的源代码级在操作,该机制允许我们在有源代码的情况下轻松的高性能的实现本机(Native)与托管(.Net)程序的交互。当然,尽管C++ Interop是三者中性能最高的,但是在没有源代码的情况下是无法使用这中机制的。对于笔者的这个项目,C++ Interop刚好能满足笔者的需要。

 

项目实例

Native C++ 使用OPENSSL 生成数字证书

         笔者使用的OPENSSL版本为0.9.8 下载页面为http://www.openssl.org/source/

下载并编译好OPENSSL后导入我们的C++ 工程中,我们使用如下的代码来生成证书

 

具体的源代码请参考附件

 

Code
/***********************************************************************************************************

FileName: CertificateCLI.h

Author: Lu Wei

CreateDate:2008-07-19

Description: class defination of certificate implement

*********************************************************************************************************
*/



#pragma once

using namespace System;

using namespace System::Runtime::InteropServices;



namespace CertificateCLI {



// C++/CLI class implement certificate operation

static class CertificateNative

{

private:

CertificateNative(){}

private:



//Generate Priva key , in this project it used for generate CA private key

static int GeneratePrivateKey(BYTE *bpPriKey,int *ipPriKeyLen);

//Generate PKCS#12 certificate

static int CreateP12FromPrivateKey(BYTE *bpCAPriKey, int iCAPriKeyLen, int iValidDay, BYTE *bpP12, int *ipP12Len, char *pszP12Pwd,char* pszName, char *pszSubjectName, char *pszOrganizational,char *pszOrganizationName, char *pszEmail, char *pszCountryRegion );

//Export PKCS#12 information to X509 certificate

static int ParseP12Certificate(char *szP12Pwd,BYTE *bpP12,int iP12Len,BYTE *bpOutCert,int *ipCertLen);



public:

// mid-interface with .NET lanuguage and native C++





static int GenerateP12Certificate(char* strName,char* strOrganizational,char* strOrganizationName,char* strEmail,char* strCountryRegion,char* strPassword,char* strSavePath);

static int ExportX509Certificate(char* strSource,char* strSavePath,char* strPassword);



};



// .NET class that supply Interface used by .Net language

public ref class CertificateNet

{

private:

CertificateNet(){}

public:

static System::Int32 GenerateP12Certificate(System::String^ strName, System::String^ strOrganizational, System::String^ strOrganizationName, System::String^ strEmail, System::String^ strCountryRegion,

System::String
^ strPassword, System::String^ strSavePath);

static System::Int32 ExportX509Certificate(System::String^ strSource,System::String^ strSavePath,System::String^ strPassword);

};



}



 

大家可以看到我使用了两个类来封装需要的功能,一个是native C++类,用来实现native C++openssl的交互,另一个是C++/CLI类,用来实现Native C++.Net Framework的交互。从下面这小段代码可以看出我是如何做的交互(CertificateCLI.cpp):

    对了,就是这个static_cast<char*> 。实现了我们需要的功能,不过笔者的交互比较简单,如果需要更深入交互,可能带来更多的问题,比如内存泄露之类的,更深入的研究需要读者参考MSDN。现在我们来看看怎么在C#中使用它。

Code
System::Int32 CertificateNet::ExportX509Certificate(System::String ^strSource, System::String ^strSavePath, System::String ^strPassword)

{

IntPtr ipSource
= Marshal::StringToHGlobalAnsi(strSource);

IntPtr ipSavePath
= Marshal::StringToHGlobalAnsi(strSavePath);

IntPtr ipPassword
= Marshal::StringToHGlobalAnsi(strPassword);

char *szSource = static_cast<char*>(ipSource.ToPointer());

char *szSavePath = static_cast<char*>(ipSavePath.ToPointer());

char *szPassword = static_cast<char*>(ipPassword.ToPointer());



System::Int32 status
= CertificateNative::ExportX509Certificate(szSource,szSavePath,szPassword);

return status;



}

 

 

C#中使用封装后的代码

         .Net的公共语言接口(CLI)使得我们很容易能够用C#来调用上面的代码

 

   

Code
/// <summary>

/// Export PKCS#12 file to X509 certificate

/// </summary>

/// <param name="strSource">the pfx file path</param>

/// <param name="strSavePath">where to save exported certificate</param>

/// <param name="strPassword">password</param>

/// <returns></returns>

public static int ExportP12Certificate(string strSource, string strSavePath, string strPassword)

{

int status = CertificateNet.ExportX509Certificate(strSource, strSavePath, strPassword);

return status;

}

 

这段代码显示了我们是如何调用C++/CLI生成的DLL中的方法。至此,我们实现了在C#工程中使用OPENSSL

 

结束

         在笔者的项目中,只使用很小的一部分OPENSSL代码,因此维护起来较为容易,对于更复杂的代码,需要读者更加仔细。因为在Visual Studio 2005中,当你在写C#程序时,调式程序是不可以进入到C++/CLIDLL的源代码中去的,从而使得使用笔者的方法来使用OPENSSL时必须尽可能更加严格的保证C++/CLI写的DLL的不会出错。

附录

         [1] OPENSSL的官方网站是http://www.openssl.org/,如果读者想要进一步了解OPENSSL可以去访问,不过上面的资料较少,http://www.infosecurity.org.cn/forum/index.php 中国信息安全组织论坛上面有很多不错的资料,推荐给感兴趣的读者。笔者的项目中只用到了OPENSSL中很小的一个功能,冰山一角不足以窥全貌,有不足之处,望大家海涵。

         [2] .Net 互操作性的相关资料可以参考MSDN,笔者的资料来源于李建忠老师的C++/CLI视频讲座—— Visual C++ 2005系列教 参考课程:VC++ 2005(9):非托管互操作   

[3] 由于博客园的文件大小限制,笔者无法提供编译好的LIB文件(OPENSSL),不过所有的代码都在附件里面,笔者使用的是Visual Studio 2005 SP1 编译C++C#

 

 

posted on 2008-10-30 22:19  不系舟  阅读(11652)  评论(10编辑  收藏  举报