锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 英语翻译 / 面向.NET的SSL/TLS的客户端与服务器端和SSL通道
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
技术分类
讨论组翻译
调用Office打印预览
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

锐英源精品开源心得,转载请注明:“锐英源www.wisestudy.cn,孙老师作品,电话13803810136。需要全文内容也请联系孙老师。

面向.NET的SSL/TLS的客户端与服务器端和SSL通道


前言


虽然有C语言形式的openssl开源项目能帮大家做HTTPS相关的事情,不过偏向底层,并不好用,有C#形式的封装更利于使用,本文就介绍一个在.NET下能使用的开源方案。可能大家也没机会用,不过学习下总是有好处。

 

SSPI Overview and Steps


SSPI stands for Security Support Provider Interface. It is an abstraction layer over the security services provided by windows. SSL/TLS itself is implemented in Secure Channel security provider and SSPI abstracts it for us. SSPI works by taking and returning data blobs to be sent to remote party. This way it allows us most flexibility in choosing what protocol (for ex., tcp/ip) to use and what to do with encrypted/decrypted data. One thing to be aware of is making sure the data is a stream and nothing is out of sequence. SSPI provides a number of built-in protocols Kerberos, NTLM, SSL/TLS. There is almost exactly the same sequence of function calls for either of them. In SSL/TLS case there is a little more to be done.

SSPI概述和步骤

SSPI代表安全支持提供程序接口。它是windows提供的安全服务的抽象层。SSL / TLS本身在安全通道安全提供程序中实现,SSPI为我们提取它。SSPI通过获取和返回要发送到远程方的blob数据来工作。这样,它允许我们在选择使用什么协议(例如,tcp / ip)以及如何处理加密/解密数据方面具有最大的灵活性。需要注意的一件事是确保数据是一个流,顺序是重中之重。SSPI提供了许多内置协议Kerberos,NTLM,SSL / TLS。对于它们中的任何一个,几乎完全相同的函数调用序列。在SSL / TLS案例中,还有一些工作要做。


Client Side:

  • Open Certificate store. Choose what certificate to use. Call AcquireCredentialsHandle.
  • When you need to connect. Call InitializeSecurityContext. Send out data blob that is returned.
  • Go into handshake loop with remote party by calling InitializeSecurityContext passing in received data blobs and sending out returned data blobs until success is returned.
  • When need to send data out, call EncryptMessage and send returned encrypted data blob to remote party.
  • When need to decrypt received data, call DecryptMessage and process decrypted data blob
  • When done, call ApplyControlToken with SCHANNEL_SHUTDOWN. Call InitializeSecurityContext
    and send out returned data blob.

客户端:

  • 打开证书商店。选择要使用的证书。调用AcquireCredentialsHandle。
  • 当你需要连接时。调用InitializeSecurityContext。发送返回的blob数据。
  • 通过调用InitializeSecurityContext传入接收到的blob数据并发送返回的blob数据,直到返回成功,进入与远程方的握手循环。
  • 当需要发送数据时,调用EncryptMessage并将返回的加密blob数据发送给远程方。
  • 当需要解密接收的数据时,调用DecryptMessage并处理解密的blob数据
  • 完成后,调用ApplyControlToken跟SCHANNEL_SHUTDOWN。调用InitializeSecurityContext
    并发送返回的blob数据。

Server Side:

  • Open Certificate store. Choose what certificate to use. Call AcquireCredentialsHandle.
  • When you receive new connection from client, call AcceptSecurityContext. Send out data blob that is returned.
  • Go into handshake loop with remote party by calling AcceptSecurityContext passing in received data blobs and sending out returned data blobs until success is returned.
  • When need to send data out, call EncryptMessage and send returned encrypted data blob to remote party.
  • When need to decrypt received data, call DecryptMessage and process decrypted data blob
  • When done, call ApplyControlToken with SCHANNEL_SHUTDOWN. Call AcceptSecurityContext and send out returned data blob.

These basically are the steps that have to be taken to use SSL/TLS with SSPI. There are some details that need to be taken care of in the code that is not listed above. Such as respond appropriately to any error codes returned by SSPI functions. For example, renegotiation, disconnection, having read incomplete message/too much data (that is one complete message and extra data from next message).

服务器端:

  • 打开证书商店。选择要使用的证书。打电话AcquireCredentialsHandle。
  • 当您从客户端收到新连接时,请致电AcceptSecurityContext。发送返回的数据blob。
  • 通过调用AcceptSecurityContext传入接收到的数据blob并发送返回的数据blob,直到返回成功,进入与远程方的握手循环。
  • 当需要发送数据时,调用EncryptMessage并将返回的加密数据blob发送给远程方。
  • 当需要解密接收的数据时,调用DecryptMessage并处理解密的数据blob
  • 完成后,打电话ApplyControlToken跟SCHANNEL_SHUTDOWN。调用AcceptSecurityContext并发送返回的数据blob。

这些基本上是在SSPI中使用SSL / TLS必须采取的步骤。在上面未列出的代码中需要注意一些细节。例如适当地响应SSPI函数返回的任何错误代码。例如,重新协商,断开连接,读取不完整的消息/过多的数据(即一条完整的消息和下一条消息中的额外数据)。

OpenSSL


OpenSSL is an open source project for commercial-grade, full featured implementation of SSL/TLS. You can read more about it at: ttp://www.openssl.org/ (Documentation at: http://www.openssl.org/docs, Source at: http://www.openssl.org/source)
OpenSSL是一个开源项目,用于商业级,全功能的SSL / TLS实现。
First let's compile the OpenSSL library. Download the latest distribution for example openssl-0.9.7b.tar.gz首先让我们编译OpenSSL库。下载最新的发行版,例如openssl -0.9.7b.tar.gz

  • Extract the files. Read INSTALL.W32 file in the OpenSSL root directory.
  • Open "Visual Studio .NET Command Prompt" window.
  • Go into openssl-0.9.7b directory.
  • Type "perl Configure VC-WIN32" in the OpenSSL root directory. (Install ActivePerl for windows if you don't have it)
  • Type "ms\do_ms" in the OpenSSL root directory.
  • Now type "nmake -f ms\nt.mak" (This is for static version of OpenSSL library)
  • 提取文件。阅读在OpenSSL根目录的INSTALL.W32文件。
  • 打开“ Visual Studio .NET Command Prompt”窗口。
  • 进入openssl -0.9.7b目录。
  • OpenSSL根目录中键入“perl Configure VC-WIN32 ” 。(ActivePerl如果没有,请安装)
  • ms\do_ms在OpenSSL根目录中键入“ ” 。
  • 现在输入“ nmake -f ms\nt.mak”(这是针对OpenSSL库的静态版本)

 

Everything should build nicely and .libs should be outputed into openssl-0.9.7b\out32 directory.

  • Set this directory in your "VC++ Directories" option for the "Library Files".
  • Set openssl-0.9.7b\inc32\ directory in your "VC++ Directories" option for the "Include Files".
  • Rename the generated libraries to libeay32r.lib and ssleay32r.lib for Release mode. Build separate one
  • for Debug mode with /MDd. They are NOT interchangable.

一切都应该很好地构建,.libs应该输出到openssl-0.9.7b\out32目录中。

  • 在“ VC++ Directories”选项的“ ”选项中设置此目录Library Files。
  • 在“ VC++ Directories”选项下Include Files设置目录中加上openssl-0.9.7b\inc32\。
  • 为发行模式重命名生成的库libeay32r.lib和ssleay32r.lib。逐一编译生成
  • 对于调试模式带上/ MDd选项。它们不可互换。

At this point the Managed C++ project should compile without problems.

  • Read the OpenSSL FAQ on how to create certificates with openssl.exe or you can search google for more information and examples. For example if you're using MS CA you can download CA certificate from http://131.107.152.153/ save it to CA.cer file and use it in the sample code for CA file parameter.

此时,Managed C ++项目应该没有问题地编译。

  • 阅读有关如何使用openssl .exe 创建证书的OpenSSL 常见问题解答,或者您可以搜索谷歌以获取更多信息和示例。例如,如果您使用的是MS CA,则可以从http://131.107.152.153/下载CA证书,并将其保存到CA.cer文件,并将其用于CA文件参数的示例代码中。

Now let's issue a certificate request to this CA.

  • First generate the key as in the above FAQ: "openssl genrsa -des3 -out privkey.pem 2048"
  • Now generate the request "openssl req -new -key privkey.pem -out cert.csr"
  • Using the "advanced certificate request" form on the MS CA web site, choose "Submit a certificate request by using a base-64-encoded CMC or PKCS #10 file, or submit a renewal request by using a base-64-encoded PKCS #7 file." link. Tell it where to find the .csr file and select submit. Now download the generated certificate.
  • Convert it to .pem "openssl x509 -inform DER -in certnew.cer -out clientcert.pem"
  • Combine certificate and private key into one file. "type clientcert.pem privkey.pem >client.pem"

现在让我们向这个CA发出证书请求。

  • 首先生成上述FAQ中的密钥:“ openssl genrsa -des3 -out privkey.pem 2048”
  • 现在生成请求“ openssl req -new -key privkey.pem -out cert.csr”
  • 使用MS CA网站上的“ advanced certificate request”表单,选择“使用base-64编码的CMC或PKCS#10文件提交证书请求,或使用base-64编码的PKCS#7文件提交续订请求“链接。告诉它在哪里找到.csr文件并选择提交。现在下载生成的证书。
  • 将其转换为.pem“ openssl x509 -inform DER -in certnew.cer -out clientcert.pem”
  • 将证书和私钥组合到一个文件中。“ type clientcert.pem privkey.pem >client.pem”

Now you're ready to use this client.pem for the client side. Do same steps for the server side. This is just an example.
Explore the options that suits you better.

So you need at least 2 things to get the sample project working with OpenSSL.

  • Generate client/server certificate and key into .pem format
  • Download CA certificate

There are other ways to get working certificates for testing purposes. You can explore them on your own.

现在,您已准备好将此client.pem用于客户端。对服务器端执行相同的步骤。这只是一个例子。
探索更适合您的选项。

因此,您需要至少两件事才能使示例项目与OpenSSL一起使用。

  • 生成客户端/服务器证书并将密钥转换为.pem格式
  • 下载CA证书

还有其他方法可以获得用于测试目的的工作证书。您可以自己探索它们。

How to get Certificates: 如何获得证书

When you're ready to deploy your app you can order a real/verifiable certificate from http://www.verisign.com/or http://www.thawte.com/
However if you just want to play/test with SSL you have at least 3 other options.
当您准备部署应用程序时,您可以从http://www.verisign.com/http://www.thawte.com/订购真实/可验证的证书
但是,如果您只想使用SSL进行游戏/测试,则至少还有3个其他选项。

  • Best option is: Microsoft's free test Certificate Authority Server located at: http://131.107.152.153/ 

    Just click on Request a certificate. Web Browser Certificate. Use advanced Certificate form. Fill out the fields. Generate both Client and Server Authentication Certificates. Leave the defaults except for Key size, change it to bigger one if you want. You can also generate SSL test certificate for your IIS server there if you want.
  • You can explorer the options offered by OpenSSL. Check this FAQ for more info: 
    http://www.openssl.org/docs/HOWTO/certificates.txt 
  • Another option is using the built-in CA of windows 2000 Server edition. You can find step by step example in ATL7 SecureSOAP Sample's readme that comes with VS.NET MSDN.
  • Yet another option is to use makecert.exe that comes with .NET SDK/PSDK. New version that comes with current PSDK supports exportable private keys (-pe option).
  1. 最佳选择是:Microsoft的免费测试证书颁发机构服务器位于:

    只需单击申请证书即可。Web浏览器证书。使用高级证书表格。填写字段。生成客户端和服务器身份验证证书。保留除密钥大小以外的默认值,如果需要,将其更改为更大的密码。如果需要,还可以为IIS服务器生成SSL测试证书。
  2. 您可以浏览OpenSSL提供的选项。有关详细信息,请查看此常见问题解答:
  3. 另一种选择是使用Windows 2000 Server版本的内置CA. 您可以在VS.NET MSDN附带的ATL7 SecureSOAP Sample自述文件中找到分步示例。
  4. 另一种选择是使用.NET SDK / PSDK附带的makecert.exe。当前PSDK附带的新版本支持可导出的私钥(-pe选项)。
  •  

To find out the Certificate's hash/thumbprint open the .cer file in explorer. Go to Details | Field | Thumbprint. Select it. Then just copy paste the byte values into your code. 要查找证书的哈希/指纹,请在资源管理器中打开.cer文件。转到详细信息| 领域| 指纹。选择它。然后只需将字节值复制粘贴到代码中即可。

Viewing Installed Certificates: 查看已安装的证书

To View your current certificates on NT: Run mmc.exe. Go to Console | Add/Remove Snap-in | Add | Certificates. Your personal or "MY" store will be under Personal | Certificates tree items.
要在NT上查看当前证书:运行mmc.exe。转到控制台| 添加/删除管理单元| 添加| 证书。您的个人或“我的”商店将在Personal | 证书树项目下面。

Client class:客户端类

class SSLConnection
{
public: 
    //initiate connection, given server's ip and client's certificate
    //hash, data to be sent will be returned in WriteSSL callback 
    void InitiateHandShake(String* ipAddress, Byte thumbPrint[], 
                           Common::Misc::SecurityProviderProtocol prot, 
                           Object* state); 
    //encrypt data, encrypted data is retuned in WriteSSL callback 
    void EncryptSend(Byte data[], int ActualLen, Object* state); 
    //decrypt data, decrypted data is returned in PlainData callback 
    void DecryptData(Byte data[], Int32 ActualSize, Object* state); 
    //disconnect from server 
    bool Disconnect(Object* state); 
    //clean up 
    void Dispose(); 
    //load new client's credentials from NewCertificate callback 
    void LoadNewClientCredentials(Byte sha1hash[]); 

public: 
    //maximum data chunk to use for send/recv at a time 
    __property int get_MaxDataChunkSize();

    //recommended initial chunk size when negotiation just starts, 
    //this is max auth token size 
    __property int get_MaxInitialChunkSize();

public: 
    //callback for encrypted data 
    WriteSSL* DoWrite; 
    //callback for decrypted data 
    PlainData* DoPlainData; 
    //optional 
    NewCertificate* DoRenegotiate; 
    //optional 
    VerifyServCert* DoServerCertVerify; 
    //optional 
    HandShakeSuccess* DoHandShakeSuccess;
    ...
};

Quick Example:快速示例


Socket sock = ...//init Socket;
SSLConnection conn = new SSLConnection();
conn.DoWrite       = new SSL.Client.WriteSSL(Send);
conn.DoPlainData   = new SSL.Client.PlainData(OnPlainData);
conn.DoRenegotiate = new SSL.Client.NewCertificate(Renegotiate);
conn.DoServerCertVerify = new SSL.Client.VerifyServCert(ServerCertVerify);
conn.DoHandShakeSuccess = new SSL.Client.HandShakeSuccess(HandShakeSuccess);
sock.Connect(....);

//try not supplying client certificate, null for thumbprint
conn.InitiateHandShake(url, null,
SSL.Common.Misc.SecurityProviderProtocol.PROT_TLS1,
Guid.Empty);
while(!connected)
{
// recv data
// call conn.DecryptData
}

string Request = "GET / HTTP/1.1\r\n" + "Host: localhost\r\n\r\n";
byte[] data = ASCIIEncoding.ASCII.GetBytes(Request);
conn.EncryptSend(data, data.Length, null);

//recv
//conn.DecryptData
conn.Disconnect(null);
conn.Dispose();

////////////////////////////////////////////////////////////////
bool Send(byte[] data, object state)
{
sock.Send(data, 0, data.Length, SocketFlags.None);
}

void OnPlainData(Byte[] data, object state)
{
//do something with decrypted data
}

void Renegotiate(SSL.Client.SSLConnection conn)
{
//server asked for client certificate
//TODO: change values to match your client's certificates hash
byte[] ThumbPrint = new Byte[] {0xBE,0xD7,0x44,0xF4,0x57,
0x54,0xF2,0x08,0x7F,0x06,
0x03,0x0B,0x01,0x33,0xE5,
0x60,0x78,0x3D,0xAF,0x35};
conn.LoadNewClientCredentials(ThumbPrint);
}

void HandShakeSuccess(){connected = true;}

void ServerCertVerify(SSL.Common.Misc.CeriticateInfo ServCertInfo)
{
X509Certificate cert = new X509Certificate(ServCertInfo.CertData);
//display server's certificate information
}

Server class:服务器类

class SSLServer
{ 
public: 
    //disconnect from given client, based on id 
    void DisconnectFromClient(Guid ClientID, Object* state); 
    //clean up 
    void Dispose(); 
    //encrypt data, encrypted data is retuned in WriteSSL callback 
    void EncryptSend(Byte data[], int ActualLen, Guid ClientID, 
                     Object* state); 
    //decrypt data, decrypted data is returned in PlainData callback 
    void DecryptData(Byte data[], Int32 ActualLen, Guid ClientID, 
                     Object* state); 
    //remove client based on id from internal list of clients 
    void RemoveClient(Guid ClientID); 
    //maximum data chunk to use for send/recv at a time 
    int MaxDataChunkSize(Guid ClientID);
    //setup credentials, certThumbPrint is certificate's hash 
    void SetupCredentials(Byte certThumbPrint[], 
            Common::Misc::SecurityProviderProtocol prot); 
    //ask client to renegotiate and possibly get different credentials 
    void AskForRenegotiate(Guid ClientID, Object* state); 

public: 
    //recommended initial chunk size when negotiation just starts, 
    // this is max auth token size 
    __property int get_MaxInitialChunkSize(); 
    //ask client to provide certificate or not 
    __property void set_AskClientForAuth(bool value); 

public: 
    //callback for encrypted data 
    WriteSSL* DoWrite; 
    //callback for decrypted data 
    PlainData* DoPlainData; 
    //optional 
    VerifyClientCert* DoClientCertVerify; 
    //optional 
    HandShakeSuccess* DoHandShakeSuccess; 

private:
    ...
};

Quick Example:快速示例

          SSLServer SSL    = new SSLServer();
SSL.DoPlainData = new SSL.Server.PlainData(OnPlainData);
SSL.DoWrite     = new SSL.Server.WriteSSL(OnSend);
SSL.DoClientCertVerify
= new SSL.Server.VerifyClientCert(OnClientCertInfo);
SSL.DoHandShakeSuccess
= new SSL.Server.HandShakeSuccess(OnClientHandShakeSuccess);
SSL.AskClientForAuth = false; //TODO: change values to match your server's certificates hash
byte[] ServerCertThumbPrint = new byte[]{0xA4, 0x01, 0xC2, 0xB1, 0x73,
0xD9, 0xD9, 0xF4, 0x77, 0x68,
0x60, 0xE5, 0xAD, 0x25, 0x34,
0xEE, 0x59, 0xEB, 0x0E, 0x8D};
SSL.SetupCredentials(ServerCertThumbPrint,
SSL.Common.Misc.SecurityProviderProtocol.PROT_TLS1);
//listen for incoming connections on Socket
//Accept new connection if any
//begin receiving data from client
Guid clientID = Guid.NewGuid();
SSL.DecryptData(buff, bytesRead, clientID, null);
SSL.DisconnectFromClient(clientID);
//When client handshake complete,
//do SSL.EncryptSend(data, data.Length, ClientID, null); when needed
SSL.Dispose();

////////////////////////////////////////////////////////////////
void OnPlainData(byte[] data, Guid ClientID, object o)
{
//process data
}

bool OnSend(byte[] data, Guid ClientID, object o)
{
//send data out on socket
}

void OnClientCertInfo(SSL.Common.Misc.CeriticateInfo clientCert)
{
X509Certificate cert = new X509Certificate(clientCert.CertData);
//display client's cert info
}

void OnClientHandShakeSuccess(Guid ClientID)
{
// handshake with client is successful
}

SSL Tunnel Sample: SSL通道示例

 

NOTE: Never Never try this with your real/production SQL server. Try AT YOUR OWN RISK with your test installation of db or something else that goes through known TCP/IP connection. Also, go through code see what it does, make sure it suits your specific purposes.
To use it simply build the client and server .exes. Make sure the .config file is where the .exe is. You can test how it work by securing MS SQL connection with SSL/TLS. Here are the steps to do it: Make sure you installed your own certificate and updated the hash/thumbprints in code.
Open the MS SQL Client Network utility. Go to Alias | Add, then set the options as below:

  • Server Alias: SSL
  • Network Libraries: TCP/IP
  • Server Name: Your Client.exe's IP (for ex., "localhost")
  • Port Number: Your Client's listening Port (that's the "PortToListenForRedirect" value in Client.exe.config)

In Client.exe.config "SSLDestIP" and "SSLDestPort" will be your Server.exe's IP, and port that it listens on for redirect.
In Server.exe.config "PortToListenForSSL" is port Server.exe listens on for Client.exe, and "DestIP" "DestPort" are MS SQL Servers real IP and Port where everything from client will be sent. So the Cnnection in between client and exe will be secure. Client.exe will run on local machine for example and Server.exe will run on machine closer to SQL Server.
Run the SSL Client/Server applications.
Open the MS SQL Enterprise Manager console. Choose "New SQL Server registration". For server name put SSL, fill in the login info. Click OK. Now, you should be connected through SSL to your SQL Server.
注意:永远不要尝试使用您的真实/产品SQL服务器。尝试安装db或其他通过已知TCP / IP连接的东西,自行承担风险。此外,通过代码查看它的作用,确保它符合您的特定目的。
要使用它,只需构建客户端和服务器.exes。确保.config文件是.exe所在的位置。您可以通过使用SSL / TLS保护MS SQL连接来测试其工作方式。以下是执行此操作的步骤:确保安装了自己的证书并更新了代码中的哈希/指纹。
打开MS SQL客户端网络实用程序。转到Alias | 单击添加,然后设置如下选项:

  • 服务器别名:SSL
  • 网络库:TCP / IP
  • 服务器名称:您的Client.exe的IP(例如,“localhost”)
  • 端口号:客户端的侦听端口(即Client.exe.config中的“PortToListenForRedirect”值)

在Client.exe.config中,“SSLDestIP”和“SSLDestPort”将是您的Server.exe的IP,以及它侦听重定向的端口。
在Server.exe.config中,“PortToListenForSSL”是Server.exe侦听Client.exe的端口,“DestIP”“DestPort”是MS SQL Server真实IP和端口,其中发送来自客户端的所有内容。因此,客户端和exe之间的连接将是安全的。例如,Client.exe将在本地计算机上运行,​​Server.exe将在靠近SQL Server的计算机上运行。
运行SSL客户端/服务器应用程序。
打开MS SQL企业管理器控制台。选择“新建SQL Server注册”。对于服务器名称放置SSL,请填写登录信息。单击确定。现在,您应该通过SSL连接到SQL Server。

版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内