|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Samples that use MS SSPI SSL:
Samples that use OpenSSL:
Contents:
SSPI Overview and StepsSSPI 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. Client Side:
Server Side:
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). OpenSSLOpenSSL 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) First let's compile the OpenSSL library. Download the latest distribution for example openssl-0.9.7b.tar.gz
Everything should build nicely and .libs should be outputed into
At this point the Managed C++ project should compile without problems.
Now let's issue a certificate request to this 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.
There are other ways to get working certificates for testing purposes. You can explore them on your own.
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.
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.
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.
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: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. References:
MS SChannel related:
Disclaimer: THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. | ||||||||||||||||||||