I'm trying to work with SSL manually without using libs as OpenSSL etc... And I have fault on 1st step with Hello message from client.
From technet:
It must consist of:
ClientVersion 3,1
ClientRandom[32]
SessionID: None (new session)
Suggested Cipher Suites:
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_DES_CBC_SHA
Suggested Compression Algorithm: NONE
In my code ( C/C++ ), I have created message on this way:
char *request = "ClientVersion 3,1\r\nClientRandom[32]\r\n
SessionID: None (new session)\r\n
Suggested Cipher Suites:\r\n
TLS_RSA_WITH_3DES_EDE_CBC_SHA\r\n
TLS_RSA_WITH_DES_CBC_SHA\r\n
Suggested Compression Algorithm: NONE\r\n";
But after recv() functions, I've got 0 in result, so what's wrong in my message structure?
PS
In HTTP-proto there is a place, when must be double \r\n ( which splits the headers and the body message ), may be, there must be something like this or not?
You need to take a good look at RFC 2246, rather than just making things up. For example the newlines between the elements of the message are a figment of your imagination.
But why you think you can work with SSL 'manually' is a mystery. You can't, and you don't need to. Reimplementing SSL is a major task and you don't have the resources to do it. Use your library: OpenSSL, JSSE, etc.
Related
I want to decrypt TLS traffic in a pcap file using scapy by providing certificate and private key.
But i dont have a clue how to do it without using wireshark or tshark
Could someone give me some suggestions? Thanks in advance.
The three things you might want to look at are:
TLSSession: https://scapy.readthedocs.io/en/latest/usage.html?highlight=tlssession#advanced-sniffing-sniffing-sessions - i.e. how to dissect "on-the-flow" using a session in Scapy
Scapy's TLS notebooks: https://github.com/secdev/scapy/tree/master/doc/notebooks/tls - they have prety detailed explanations and examples regarding dissection/decryption
This test case in scapy: https://github.com/secdev/scapy/blob/3040f6d705176731494a7bcf76b820f077716729/test/tls.uts#L1166-L1218 that puts it all together.
The key steps are (from the last test case):
>>> key = PrivKeyRSA("srv_key.pem")
>>> res = sniff(offline="tls.pcap", session=TLSSession(server_rsa_key=key))
Obviously this only makes sense when using RSA and not Diffie-Hellman. Good luck !
My question for today: is there an official way to obtain peer ssl socket information (peer certificate to be exact) in cowboy_http_handler's Handler:handle(Req, State)?
Of course, I can scrape Req tuple (peer socket is the second field as of today) with erlang:element/2, but this is not future-proof and just doesn't look right.
Thanks in advance!
There is an exported call:
cowboy_req:get(socket, Req)
It returns the socket, or just about everything else there is in the Req object, currently:
bindings
body_state
buffer
connection
headers
host
host_info
meta
method
multipart
onresponse
path
path_info
peer
pid
port
qs
resp_body
resp_compress
resp_headers
resp_state
socket
transport
version
I'm not sure if it is in the documentation, I can't see it, but it's a lot better and less likely to fail than just getting a numbered element value out, and you can always add a unit test that checks that it works, so if it does get stamped/broken at some point you get a heads up. I don't expect it'll go anywhere though.
Recently, I was able to get MD5 authentication working for XMPP streams in Swift IOS following the instructions on the following two websites (I used the CC-MD5 function of Apple's CommonCrypto C library for the actual hashing):
http://wiki.xmpp.org/web/SASLandDIGEST-MD5
http://www.deusty.com/2007/09/example-please.html
I'm searching for a similar explanation for how to get other hashed SASL authentication schemes working, especially SCRAM-SHA1. I have found the official RFC5802 document but I'm having a lot of trouble understanding it (it is not specific to XMPP either). I would appreciate a simpler explanation or some simple readable code (C, PHP, C++, Javascript, Java) specific to XMPP authentication that doesn't use libraries for anything other than the actual hashing.
I'm interested in understanding the process and am not looking to use the ios XMPP-Framework. Any help would be appreciated.
SCRAM-SHA-1
The basic overview of how this mechanism works is:
The client sends the username it wants to authenticate as.
The server sends back the salt for that user and the number of iterations (either by generating them or looking them up in its database for the given username).
The client hashes the password with the given salt for the given number of iterations.
The client sends the result back.
The server does a variation of the hashing and sends it result back to the client, so the client can also verify that the server had the password/a hash of the password.
The cryptographic algorithms you'll need are SHA-1, HMAC with SHA-1 and PBKDF2 with SHA-1. You should look up how to use them in your language/framework, as I don't recommend implementing them from scratch.
In detail
First normalize the password (using SASLprep), this will be normalizedPassword. This is to ensure the UTF8 encoding can't contain variations of the same password.
Pick a random string (for example 32 hex encoded bytes). This will be clientNonce.
The initialMessage is "n=" .. username .. ",r=" .. clientNonce (I'm using .. for string concatenation).
The client prepends the GS2 header ("n,,") to the initialMessage and base64-encodes the result. It sends this as its first message:
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="SCRAM-SHA-1">
biwsbj1yb21lbyxyPTZkNDQyYjVkOWU1MWE3NDBmMzY5ZTNkY2VjZjMxNzhl
</auth>
The server responds with a challenge. The data of the challenge is base64 encoded:
<challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
cj02ZDQ0MmI1ZDllNTFhNzQwZjM2OWUzZGNlY2YzMTc4ZWMxMmIzOTg1YmJkNGE4ZTZmODE0YjQyMmFiNzY2NTczLHM9UVNYQ1IrUTZzZWs4YmY5MixpPTQwOTY=
</challenge>
The client base64 decodes it:
r=6d442b5d9e51a740f369e3dcecf3178ec12b3985bbd4a8e6f814b422ab766573,s=QSXCR+Q6sek8bf92,i=4096
The client parses this:
r= This is the serverNonce. The client MUST ensure that it starts with the clientNonce it sent in its initial message.
s= This is the salt, base64 encoded (yes, this is base64-encoded twice!)
i= This is the number of iterations, i.
The client computes:
clientFinalMessageBare = "c=biws,r=" .. serverNonce
saltedPassword = PBKDF2-SHA-1(normalizedPassword, salt, i)
clientKey = HMAC-SHA-1(saltedPassword, "Client Key")
storedKey = SHA-1(clientKey)
authMessage = initialMessage .. "," .. serverFirstMessage .. "," .. clientFinalMessageBare
clientSignature = HMAC-SHA-1(storedKey, authMessage)
clientProof = clientKey XOR clientSignature
serverKey = HMAC-SHA-1(saltedPassword, "Server Key")
serverSignature = HMAC-SHA-1(serverKey, authMessage)
clientFinalMessage = clientFinalMessageBare .. ",p=" .. base64(clientProof)
The client base64 encodes the clientFinalMessage and sends it as a response:
<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
Yz1iaXdzLHI9NmQ0NDJiNWQ5ZTUxYTc0MGYzNjllM2RjZWNmMzE3OGVjMTJiMzk4NWJiZDRhOGU2ZjgxNGI0MjJhYjc2NjU3MyxwPXlxbTcyWWxmc2hFTmpQUjFYeGFucG5IUVA4bz0=
</response>
If everything went well, you'll get a <success> response from the server:
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
dj1wTk5ERlZFUXh1WHhDb1NFaVc4R0VaKzFSU289
</success>
Base64 decoded this contains:
v=pNNDFVEQxuXxCoSEiW8GEZ+1RSo=
The client MUST make sure the value of v is the base64 encoding of the serverSignature.
Extras
This is the basic version of the algorithm. You can extend it to do:
Channel binding. This mixes in some information from the TLS connection to the procedure to prevent MitM attacks.
Hashed storage. If the server always sends the same salt and i values, then the client can store only saltedPassword instead of the user's password. This is more secure (as the client doesn't need to store the password, just a hard to reverse salted hash) and faster, as the client doesn't need to do all the key stretching every time.
The server can also use hashed storage: the server can store only salt, i, storedKey and serverKey. More info on that here.
Possibly, also adding SCRAM-SHA-256 (though server support seems non-existent).
Pitfalls
Some common pitfalls:
Don't assume anything about the length of the nonces or salt (though if you generate them, make sure they are long enough and cryptographically random).
The salt is base64 encoded and can contain any data (embedded NULs).
Not using SASLprep may work fine for people using ASCII passwords, but it may completely break logging in for people using other scripts.
The initialMessage part of the authMessage does not include the GS2 header (in most situations, this is "n,,").
Test vectors
If you want to test your implementation, here are all the intermediate results for the example from the RFC:
Username: user
Password: pencil
Client generates the random nonce fyko+d2lbbFgONRv9qkxdawL
Initial message: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
Server generates the random nonce 3rfcNHYJY1ZVvWVs7j
Server replies: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
The salt (hex): 4125c247e43ab1e93c6dff76
Client final message bare: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j
Salted password (hex): 1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d
Client key (hex): e234c47bf6c36696dd6d852b99aaa2ba26555728
Stored key (hex): e9d94660c39d65c38fbad91c358f14da0eef2bd6
Auth message: n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j
Client signature (hex): 5d7138c486b0bfabdf49e3e2da8bd6e5c79db613
Client proof (hex): bf45fcbf7073d93d022466c94321745fe1c8e13b
Server key (hex): 0fe09258b3ac852ba502cc62ba903eaacdbf7d31
Server signature (hex): ae617da6a57c4bbb2e0286568dae1d251905b0a4
Client final message: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
Server final message: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
Server's server signature (hex): ae617da6a57c4bbb2e0286568dae1d251905b0a4
When I do something like this, apps/openssl s_client -connect 10.102.113.3:443 -ssl3, client-server communication is created using openSSL.
Now, I want to send application data from the client to the server. For example, after doing apps/openssl s_client -connect 10.30.24.45:443 -ssl3, I get something like this:
...certificate and session details...
---
GET /path/to/file
The GET /path/to/file all goes in one SSL record. I want to send it in multiple records.
I assume I have to edit apps/s_client.c, and find the place where the SSL_write or similar happens.
How do I go about something like that?
For a properly designed application the TCP packet sizes and SSL frame sizes should not matter. But there are badly designed applications out there which expect to get like the HTTP request inside a single read, which often means that it must be inside the same SSL frame. If you want to run tests against applications to check for this kind of behavior you either have to patch your s_client application or you might use something else, like
#!/usr/bin/perl
use strict;
use IO::Socket::SSL;
my $sock = IO::Socket::SSL->new('www.example.com:443') or die "$!,$SSL_ERROR";
print $sock "GE";
print $sock "T / HT";
print $sock "TP/1.0\r\n\r\n";
This will send the HTTP request header within 3 SSL frames (which might still get put together into the same TCP packet). Since on lots of SSL stacks (like OpenSSL) one SSL_read reads only a single SSL frame this will result in 3 reads necessary to read the full HTTP request.
Okay, I figured out that I needed to change the number of bytes I'm writing using the SSL_write.
This is a code snippet, starting at line 1662 of s_client.c:
if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds))
{
k=SSL_write(con,&(cbuf[cbuf_off]), (unsigned int)cbuf_len);
.......
}
To make the application data be sent in multiple records instead of just the one, change the last parameter in the SSL_write.
For example, do this:
if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds))
{
k=SSL_write(con,&(cbuf[cbuf_off]), 1);
.......
}
This will result in something like this:
Notice the multiple records for Application Data instead of just the one.
I'm trying to send a request with:
ActiveXObject("WinHttp.WinHttpRequest.5.1")
however this requires a client certificate to do so (which we have been provided).
Having tested in PHP cURL I can do so with:
curl_setopt($SOAP, CURLOPT_SSLCERT,$filepathtocertificate);
Which works fine. However I must use IIS running asp(javascript) and point to the certificate store of the machine the script is running on with:
SetClientCertificate("LOCAL_MACHINE\\Personal\\Certificate subject");
for our actual deployment. The MS documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/aa384055(v=vs.85).aspx) suggests that the path above has to state the 'subject' of the certificate, however the certificate seems to have several subjects and no combination of several or all of them seems to yeild any results and I am stuck with the following error before the request is even sent:
WinHttp.WinHttpRequest error '80072f0c'
A certificate is required to complete client authentication
Looking in the certificate store and using other scripts in the same folder show they are definitely there but have subjects like:
C=US, O=Organisation NAme, OU="Another Organisation Name, Inc.", CN=Organisation Name Root
Or similar.
Any advice on what parameters SetClientCertificate needs to be given to select and send certificates in the certificate store would be much appreciated.
I had a lot of trouble with this same issue - using winhttp 5.1 from a scripting language to set a client certificate before a send.
I had used mmc with the certificates snap-in to import the certificate in CURRENT_USER \ Personal - but the Winhttp SetClientCertificate didn't seem to be doing anything, nor was I able to pick up any error code or message so it was a case of repeated trial and error - the SetClientCertificate string should be something like "Location\store\subject" eg "CURRENT_USER\Personal\My Certificate" (or \ \ if your language requires \ to be escaped) -the final part being 'subject' which is not as clear as it should be. Under MMC the subject is broken into many elements.
I eventually got it working by dropping the location and store - they were the defaults so I may have been fortunate - and providing just the subject field - the value I used for the subject field was the value in the line "CN = " under subject (when the cert is opened under mmc) - but this (perhaps coincidentally) was also the value in the 'Issued To' column on the main mmc certificate list. In my case it worked - clearly if there is a cert with these two values different then you'd need to try each.
Hope this helps if somebody is similarly stuck.
This is a very old question yet I had to find an answer today. The answer provided above by #JSL helped me. If you only provide the certificate subject name then it works! So it is clear that there is a mistake in the way full path is specified.
I got the right info for Windows 7 from this link https://msdn.microsoft.com/en-us/library/windows/desktop/aa384076(v=vs.85).aspx
here is VBA script that works.
Dim objHttp As New WinHttp.WinHttpRequest
objHttp.Open "GET", url, False
objHttp.SetClientCertificate "CURRENT_USER\My\TestCert"
objHttp.send
Valid locations are LOCAL_MACHINE and CURRENT_USER and
Valid store names are "MY", "Root", and "TrustedPeople".
Remember to escape the backslashes in C++, C# etc.