精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
锐英源精品开源心得,转载请注明:“锐英源www.wisestudy.cn,孙老师作品,电话13803810136。需要全文内容也请联系孙老师。
虽然有C语言形式的openssl开源项目能帮大家做HTTPS相关的事情,不过偏向底层,并不好用,有C#形式的封装更利于使用,本文就介绍一个在.NET下能使用的开源方案。可能大家也没机会用,不过学习下总是有好处。
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代表安全支持提供程序接口。它是windows提供的安全服务的抽象层。SSL / TLS本身在安全通道安全提供程序中实现,SSPI为我们提取它。SSPI通过获取和返回要发送到远程方的blob数据来工作。这样,它允许我们在选择使用什么协议(例如,tcp / ip)以及如何处理加密/解密数据方面具有最大的灵活性。需要注意的一件事是确保数据是一个流,顺序是重中之重。SSPI提供了许多内置协议Kerberos,NTLM,SSL / TLS。对于它们中的任何一个,几乎完全相同的函数调用序列。在SSL / TLS案例中,还有一些工作要做。
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).
这些基本上是在SSPI中使用SSL / TLS必须采取的步骤。在上面未列出的代码中需要注意一些细节。例如适当地响应SSPI函数返回的任何错误代码。例如,重新协商,断开连接,读取不完整的消息/过多的数据(即一条完整的消息和下一条消息中的额外数据)。
Everything should build nicely and .libs should be outputed into openssl-0.9.7b\out32 directory.
一切都应该很好地构建,.libs应该输出到openssl-0.9.7b\out32目录中。
At this point the Managed C++ project should compile without problems.
此时,Managed C ++项目应该没有问题地编译。
Now let's issue a certificate request to this CA.
现在让我们向这个CA发出证书请求。
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.
There are other ways to get working certificates for testing purposes. You can explore them on your own.
现在,您已准备好将此client.pem用于客户端。对服务器端执行相同的步骤。这只是一个例子。
探索更适合您的选项。
因此,您需要至少两件事才能使示例项目与OpenSSL一起使用。
还有其他方法可以获得用于测试目的的工作证书。您可以自己探索它们。
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个其他选项。
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文件。转到详细信息| 领域| 指纹。选择它。然后只需将字节值复制粘贴到代码中即可。
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 | 证书树项目下面。
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; ... };
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
}
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: ... };
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
}
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:
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 | 单击添加,然后设置如下选项:
在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。