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 |
Related
I am writing a simple TLS client/server program to securely communicate over the network. Initially I am building and running both the client and server on the same machine running RHEL 8.2.
First, I am using custom self signned ssl certificate and key for my programs. I have placed the rootCA.crt (my custom CA certificate in /root/CA/rootCA.crt). Also copied the rootCA.pem to /etc/pki/ca-trust/source/anchors/ and executed update-ca-trust enable then update-ca-trust extract to install the certificate to the system. (Not sure if I need to reboot the system for it to take effect.)
Initially, the client and server were able to communicate usint TLS untill I added the certificate validation part of the code on the client side.
Certificate Verification snippet:
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_verify_depth(ctx, 4);
const long flags = SSL_OP_NO_SSLv2 |
SSL_OP_NO_SSLv3 |
SSL_OP_NO_TLSv1 |
SSL_OP_NO_TLSv1_1 |
SSL_OP_NO_COMPRESSION;
SSL_CTX_set_options(ctx, flags);
if(SSL_CTX_load_verify_locations(ctx, NULL,
"/root/CA/") == 0){
ERR_print_errors_fp(stderr);
abort();
}
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else
{
sprintf(acClientRequest, "%s", cpRequestMessage); /* construct reply */
printf("\n\nConnected with %s encryption\n", SSL_get_ciphe
}
when I run the server and client programs I see the following error messafe =>
Onclient:
140736372886336:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1915:
On Server:
140736022137664:error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:ssl/record/rec_layer_s3.c:1543:SSL alert number 48
Not sure, what is going wrong with the certificate validation process. Can anyone suggest me how to fix this error?
Just copying your rootCA.crt file into /root/CA/ is not enough.
SSL_CTX_load_verify_locations explicitly states that the files in this directory have to use a specific format:
If CApath is not NULL, it points to a directory containing CA
certificates in PEM format. The files each contain one CA certificate.
The files are looked up by the CA subject name hash value, which must
hence be available. If more than one CA certificate with the same name
hash value exist, the extension must be different (e.g. 9d66eef0.0,
9d66eef0.1 etc). The search is performed in the ordering of the
extension number, regardless of other properties of the certificates.
Use the c_rehash utility to create the necessary links.
Therefore make sure your rootCa.crt is in PEM format. And then generate the required hash and rename it accordingly. The following command generates the hashvalue. Rename the file to <hashvalue>.0.
openssl x509 -inform PEM -subject_hash_old -in rootCa.crt | head -1
If your code then still does not work I would first test if your code works at all. For doing so change the server URL to a real server that sues an HTTPS certificate that is already trusted on your system.
I am trying to build an EAP-TLS client. I am using OpenSSL to build the TLS part of the data. Since EAP works on lower layers, I have used memory BIOs with OpenSSL to send information to Freeradius server using raw sockets. This is my code to generate client hello
ctx = SSL_CTX_new(TLSv1_client_method());
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
ssl = SSL_new(ctx);
rbio = BIO_new(BIO_s_mem());
wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);
SSL_set_connect_state(ssl);
SSL_do_handshake(ssl);
readbytes = BIO_read(wbio, buf, BUF_SIZ);
and this is what i tried to do to read the reply of the server into the same ssl:
BIO_write(rbio, temp, numbytes);
SSL_do_handshake(ssl);
readbytes = BIO_read(wbio, read, BUF_SIZ); // read is a buffer
however, when i try to send a packet using the data held in read, wireshark shows the packet as: Does anyone know why this is happening? Is this due to improper configuration of the RADIUS server? Or am I making a mistake in reading the data? According to what I read, SSL_do_handshake should be called till all the handshake steps are completed, so I dont think that there is a mistake there. Thanks a lot! Full packet sequence(use filter EAP) : http://www.filehosting.org/file/details/453553/eap-tls.pcapng
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 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.
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);