I created a SSL socket in C between a client and a host using the OpenSSL library.
I need the AES key of a SSL session to encrypt correctly a message and I can't use the standard functions ssl_write and ssl_read.
I found that there is a struct called AES_KEY, but I don't know how I can found it!
SSL_write and SSL_read work correctly only with packet type: 23 ("Application protocol")
How can I decrypt, for example, an SSL Hello Message that come from server (i opened the SSL channel with this server)? How can I encrypt an SSL Hello Client (it's in clair) that comes from an other client?
I'm trying to demonstrate an attack during the phase of "TLS Renegotiation" of TLS Protocol. I'm trying to simulate an attack MITM with a custom proxy.
Now, the server send to proxy a certain number of encrypted messages of type 22 (Handshake) and 20 (ChangeCipherSpec). How can I read these messages and decrypt them? The standard library ssl_read works only with messages 23 (Application).
Moreover, the client send to proxy a client Hello and other messages of type 22 and 20. How can I write these messages and encrypt them? I tried using ssl_write, but the server doesn't understand these messages.
Instead of manually (en|de)crypting records, you should use SSL_CTX_set_info_callback to get at the information you want.
I found the solution. The functions are:
int ssl3_read_bytes (SSL *s, int type, unsigned char *buf, int len, int peek);
int ssl3_write_bytes (SSL *s, int type, const void *buf_, int len);
Related
I'm implementing a RADIUS server with support for EAP(PEAP) authentication. The RADIUS relies on UDP and each packet will contain an EAP message with the authentication data. To simplify, each EAP (PEAP) message contains TLS packets so the client first will send an EAP packet containing TLS Client Handshake, which the server will process, and then return the TLS Server Handshake, and so on with the following packages.
I've been able to implement a simple TLS server over TCP, but what I need is write TLS bytes directly in the SSL connection.
SSLConn_init_thread();
SSL_load_error_strings();
ERR_load_crypto_strings();
SSL_library_init();
SSL_CTX *ctx;
...
ctx = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_use_PrivateKey(...);
SSL_CTX_use_certificate(...);
ssl = SSL_new(ctx); // I want to read/write TLS packets directly with this object
I've looked into OpenSSL docs but it's not very well documented. In this guide says one can make the handshake "by hand" using the SSL_set_accept_state() with SSL_read and SSL_write, but I don't understand exactly how to do that.
Any advice with this or about handling OpenSSL connections without relying on TCP would be very appreciated.
I ended up reading the book Network Security with OpenSSL and found Memory BIOs were what i needed.
Network Security With OpenSSL
A memory BIO treats a memory segment the same as a file or socket, and can be created by using
BIO_s_mem to obtain a BIO_METHOD object suitable for use with BIO_new and BIO_set
BIO_s_mem()
BIO_s_mem() return the memory BIO method function.
A memory BIO is a source/sink BIO which uses memory for its I/O. Data written to a memory BIO is stored in a BUF_MEM structure which is extended as appropriate to accommodate the stored data.
Any data written to a memory BIO can be recalled by reading from it. Unless the memory BIO is read only any data read from it is deleted from the BIO.
Basically you can read/write encrypted data directly to the SSL connection using the memory BIOs:
// setup SSL_context...
ssl = SSL_new(ctx);
// Create read/write BIOs
rbio = BIO_new(BIO_s_mem());
wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);
if (/* Server */) {
SSL_set_accept_state(ssl);
} else {
SSL_set_connect_state(ssl);
}
To write/read from BIOs:
BIO_read(wbio, buffer, strlen(buffer));
BIO_write(wbio, buffer, strlen(buffer));
In ascii diagram terms, here's what the flow of bytes loops like. SSL_read/SSL_write are used to pass unencrypted bytes in-to/out-of the SSL object, and BIO_read/BIO_write are used to get corresponding encrypted bytes in-to/out-of the SSL object. It's the up to you to then transfer the encrypted bytes over a network connection.
Git hub example of non blocking sockets / SSL
(https://gist.github.com/darrenjs/4645f115d10aa4b5cebf57483ec82eca)
+------+ +-----+
|......|--> read(fd) --> BIO_write(rbio) -->|.....|--> SSL_read(ssl) --> IN
|......| |.....|
|.sock.| |.SSL.|
|......| |.....|
|......|<-- write(fd) <-- BIO_read(wbio) <--|.....|<-- SSL_write(ssl) <-- OUT
+------+ +-----+
| | | |
|<-------------------------------->| |<------------------->|
| encrypted bytes | | unencrypted bytes |
I'm using OpenSSL in order to encrypt some emails, that a piece of hardware sends. But, whenever I try to call SSL_connect(), I get :
SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
After sending "EHLO" and "STARTTLS" I call the following function:
SSL_CTX *ctx = NULL;
SSL *ssl = NULL;
void CreateTLSSession(int sockfd)
{
printf("///////////////creating TLS Session/////////////////////\n");
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL)
{
printf("failed to initialize context\n");
return;
}
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
ssl = SSL_new(ctx);
if (!SSL_set_fd(ssl, sockfd))
{
printf("failed to bind to socket fd\n");
return;
}
if (SSL_connect(ssl) < 1)
{
ERR_print_errors_fp(stdout);
fflush(stdout);
printf("SSL_connect failed\n");
return;
}
}
I've tried connecting to :
smtp.live.com : 587 --> SSL routines:SSL23_GET_SERVER_HELLO:unknown
protocol s23_clnt.c:787:
smtp.live.com : 25 --> SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol s23_clnt.c:787:
smtp.gmail.com : 587 --> SSL routines:SSL23_GET_SERVER_HELLO:unknown
protocol s23_clnt.c:787:
smtp.gmail.com : 465 --> no response from server at all!
smtp.gmail.com : 25 --> SSL routines:SSL23_GET_SERVER_HELLO:unknown
protocol s23_clnt.c:787:
I've tried different ports, since some similar questions on this SO suggested, that such error is usually related to using the wrong port for SSL.
Am I missing something here?
UPDATE:
All other methods (i.e. TLSv1_1_method(), SSLv3_method() ...) lead to SSL3_GET_RECORD:wrong version number
UPDATE:
I was able to observe the following on wireshark:
"EHLO"
"at your service"
"STARTTLS"
"Ready to starttls"
-->now I call the above function
unreadable request (encrypted)
unreadable reply (encrypted)
--> ERROR
SMTP servers on ports 587 and 25 are usually plain text and will switch to TLS only after the initial SMTP dialog and a STARTTLS command from the client. And trying SSL_connect on the plain text socket will fail.
Another way to solve this problem may be to run your C program under Scott Gifford's sslclient (see http://www.superscript.com/ucspi-ssl/sslclient.html). sslclient will spawn your program and open an tcp connection to the server, and pipe your program's stdout to the server, and pipe output from the server to your program's stdin. He has a patched version for TLS that will start the connection off in plain text, then once the two sides have agreed on STARTTLS, your program can signal to sslcient to enable SSL encryption on the connection by writing a command to a file descriptor for this purpose. The nice thing about doing it this way is that you can let sslclient to all the heavy lifting as far as setting up the sockets and ssl, etc., and you can focus on the core function of your program.
The underlying socked was non-blocking. The problem was solved, by using select and waiting till the TLS handshake completes.
I'm making a DTLS client-server program with openssl. The program works fine, but I can't find a way to get the cipher signature after SSL handshake.
By after SSL handshake, I mean in the client side, after:
if (SSL_connect(ssl) <= 0)
{
//error handling
}
In the server side, after:
do
{
ret = SSL_accept(ssl);
} while (ret == 0);
I can see the actual cipher signature is sha256WithRSAEncryption from the captured DTLS packets, but how to get this information from openssl?
Note that even though I'm using DTLS protocol, the code is almost the same as TLS/SSL.
Cipher algorithm used is stored in a certificate. So when you have a certificate (x509), the type of cipher algorithm can be extracted. Numeric version only:
X509_get_signature_type(client_cert)
To get human readable string, convert the return value of the previous function with this:
OBJ_nid2ln(X509_get_signature_type(client_cert))
I have two embedded systems running Angstrom Linux that are connected via a Ethernet cross-over cable. I'm developing a C program that will allow the two systems to communicate with each other.
When the two computers talk to each other they first need to verify the identity of the other and encrypt the connection. I'm trying to use openssl to accomplish the authentication and encryption but I'm not totally sure what to do.
All the peer to peer questions are related to other languages or aren't related to openssl.
I’ve been trying to modify the code from An Introduction to OpenSSL Programming http://www.linuxjournal.com/article/4822 to get my embedded systems working, but haven’t been successful. The in the SSL_CTX *initialize_ctx which is in common.c and also load_dh_params(ctx,file) in server.c seem to be the problem areas. Here is my code for common.c with some of my modifications.
SSL_CTX *initialize_ctx(keyfile,password)
char *keyfile;
char *password;
{
SSL_METHOD *meth;
SSL_CTX *ctx;
char buffer[200];
if (!bio_err)
{
/* Global system initialization*/
SSL_library_init();
SSL_load_error_strings();
/* An error write context */
bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
}
debuglocation(__LINE__,__FILE__);
/* Set up a SIGPIPE handler */
signal(SIGPIPE,sigpipe_handle);
/* Create our context*/
meth=SSLv23_method();
ctx=SSL_CTX_new(meth);
debuglocation(__LINE__,__FILE__);
/* Load our keys and certificates*/
// if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile)))
// berr_exit("Can't read certificate file");
debuglocation(__LINE__,__FILE__);
pass=password;
/* TODO need to put a password on the key*/
//SSL_CTX_set_default_passwd_cb(ctx,password_cb);
//if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM)))
//http://www.openssl.org/docs/ssl/SSL_CTX_use_certificate.html#NOTES
if(!(SSL_CTX_use_RSAPrivateKey_file(ctx,"private.pem", SSL_FILETYPE_PEM)))
berr_exit("Can't read priveate rsa");
debuglocation(__LINE__,__FILE__);
//berr_exit("Can't read key file");
// /* Load the CAs we trust*/
// if (!(SSL_CTX_load_verify_locations(ctx,
// CA_LIST,0)))
// berr_exit("Can't read CA list");
#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
SSL_CTX_set_verify_depth(ctx,1);
#endif
return ctx;
}
And here is the server.c
void load_dh_params(ctx,file)
SSL_CTX *ctx;
char *file;
{
DH *ret=0;
BIO *bio;
//http://www.openssl.org/docs/crypto/BIO_s_file.html
// opens a file just like fopen with the second parameter as the type of open. Here it is read 'r'.
if ((bio=BIO_new_file(file,"r")) == NULL)
berr_exit("Couldn't open DH file");
//http://www.openssl.org/docs/crypto/pem.html
ret=PEM_read_bio_DHparams(bio,NULL,NULL,
NULL);
BIO_free(bio);
if(SSL_CTX_set_tmp_dh(ctx,ret)<0)
berr_exit("Couldn't set DH parameters");
}
My debuglocation function looks like this.
int debuglocation(int line, char * file)
{
static char c = 'A';
printf("Made it to line %d in %s call it %c\n",line,file, c);
c++;
return 0;
}
So when I run all that I get from the server.
2535:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1075:
And this from the client.
SSL connect error
2616:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:596:
Also I’m not sure what ssl commands to use to make the needed certificates.
It seemed like RSA would work well if both the embedded devices had one public and one priviate key, so I tried following http://www.devco.net/archives/2006/02/13/public_-_private_key_encryption_using_openssl.php
and made a script to make them for me.
openssl genrsa -out private.pem 1024
openssl rsa -in private.pem -out public.pem -outform PEM -pubout
Thanks in advance for the help. If you need more information please let me know. I think that answers to this question could be really helpful to anyone developing in C for an embedded system who needs some authentication.
Anthony
As the user that runs the comm process, do ssh_keygen.
Append the public part of the output, id_rsa.pub, to the ~/.ssh/authorized_keys on the other machine. Now you can run remote programs using ssh without logging in.
Edit. I suggested the above because of the hassle of working with certs. You need to have a trust store, correct directory permissions, etc. I think the first thing you're missing is loading the data on trusted certificates. See the link on how to do that. It's easier to check the authorization using the command line tools in openssl then to debug your program and get the SSL set up at the same time.
I ended up using ssh rather than trying to use openssl. It did make life much simpler. Maybe when I have more time I will figure it out the other way.
Here is a telnet site:
telnet://202.85.101.136:8604/
It is from Hong Kong public library, can I write some programme to get the string / result from the telnet service, and send the request from C / Objective C? thz u.
Sure its possible. Telnet is a pretty simple protocol, you simply need to open a TCP socket and connect it to that IP and Port. When you first connect, the telnet server will send some negotiation requests using the binary protocol defined in RFC854, to which your client is expected to respond. Once negotiation is completed you communicate by simply sending and receiving ASCII data, normally a line at a time.
For a simple "get some data from a host" telnet sessions where you aren't trying to have a real interactive session, it sometimes works to simply accept all the servers negotiation settings to avoid implementing the whole negotiation protocol. To do this, just look for the server to send you several 3-byte commands in the format of: 0xFF 0xFD xx, which is basically the server telling you "I want you to use option X", just respond to this with 0xFF 0xFB xx, which basically is just you agreeing to whatever the server is asking for. Then when you get passed negotiations, you just have to receive lines with a socket read and send commands with a socket write.
If you have a telnet program already on your system, you can use it to do all the connection work for you. Here's a program for gnu/Linux that you can use as a starting point.
It uses popen to execute the system's telnet command. Then it just reads all data from the pipe (stdout if you just executed the telnet command by itself from the shell) and prints it. When there's no more data to read, it exits.
You can send data to the server by opening the pipe in rw mode instead of r and then writing like you would any other file. You could conditionally do stuff like scan your input for Username: and then send a username string too, for instance.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
const char *cmd = "telnet 202.85.101.136 8604";
char buffer[256];
FILE *pipe = popen(cmd, "r");
if( !pipe ) { perror("popen"); exit(-1); }
while( fgets(buffer, sizeof(buffer), pipe) != NULL &&
!feof(pipe) )
{
if( ferror(pipe) ) { perror("fgets"); break; }
/* Here you do whatever you want with the data. */
printf("%s", buffer);
}
pclose(pipe);
return 0;
}
If you're using Windows, this link explains the alternative to popen.
There's also a program called Expect that can help you automate stuff like this.