How get session key from ssl session - ssl

I created client and server program to exchange the data.
Client and server uses tls to pass the message securely.
Used openssl to make the connection between server and client.
Now i have the ssl handle.
Is there any way to extract server write key, server random, client random,client write key, master key.
in the below code sample Servlet method will connect to the client do the handshake get the session keys.
i am trying to read the tls packet from the port after tls handshake completed and pass the packet to another module.
To check the for malformed or invalid packets i need to decrypt the packet to inspect the payload where i required the session keys.
Is there any way to extract server write key, server random, client random,client write key, master key.
code snippet:
main(){
// Initialize the SSL library
SSL_library_init();
portnum = Argc[1];
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "mycert.pem", "mycert.pem"); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
Servlet()
{
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
unsigned char key[100];
//SSL_SESSION_get_master_key(ssl,key,100);
//printf("masterkey:%s", key);
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
buf[bytes] = '\0';
printf("Client msg: \"%s\"\n", buf);
if ( bytes > 0 )
{
if(strcmp(cpValidMessage,buf) == 0)
{
SSL_write(ssl, ServerResponse, strlen(ServerResponse)); /*
send reply */
}

Related

Openthread SRP Client in main.c

Hello I'm trying to start the SRP(Service Registration Protocol) Client in my main.c. I've found following description in openthread/srp_client.h"
* This function starts the SRP client operation.
SRP client will prepare and send "SRP Update" message to the SRP server once all the following
conditions are met:
- The SRP client is started - `otSrpClientStart()` is called.
- Host name is set - `otSrpClientSetHostName()` is called.
- At least one host IPv6 address is set - `otSrpClientSetHostName()` is called.
- At least one service is added - `otSrpClientAddService()` is called.
It does not matter in which order these functions are called. When all conditions are met, the
SRP client will wait for a short delay before preparing an "SRP Update" message and sending to
server.
* #param[in] aInstance A pointer to the OpenThread instance.
* #param[in] aServerSockAddr The socket address (IPv6 address and port number) of the SRP
* server.
*
* #retval OT_ERROR_NONE SRP client operation started successfully or it is already
running with same server
* socket address and callback.
* #retval OT_ERROR_BUSY SRP client is busy running with a different socket address.
* #retval OT_ERROR_FAILED Failed to open/connect the client's UDP socket.
*/
otError otSrpClientStart(otInstance *aInstance, const otSockAddr *aServerSockAddr);
srp_client.h
otError otSrpClientStart(otInstance *aInstance, const otSockAddr *aServerSockAddr)
otError otSrpClientSetHostName(otInstance *aInstance, const char *aName)
otError otSrpClientAddService(otInstance *aInstance, otSrpClientService *aService)
My Main.c
#include <openthread/srp_client.h>
static void SrpClientInit(void){
otSrpClientStart(**What comes in here?**, **How can i Use the EUI64 as IP?**)
otSrpClientSetHostName(**What comes in here?**, 'SrpTest')
otSrpClientAddService(**What comes in here?**,**What comes in here?**)
}
int main(int argc, char *argv[]){
....
SrpClientInit();
....
}
Can Someone explain me how i can define the parameters for the function?
This is my Code and I can Flash the Firmware but the Thread Device doesn't connect to the Thread Network anymore.
void SrpClientInit(void)
{
otSockAddr SRP_1;
SRP_1.mAddress.mFields.mComponents.mIid.mFields.m8[0] = 0xff;
SRP_1.mPort = 0xff;
otSockAddr *SRP_1_pointer = &SRP_1;
otIp6Address SRPaddr;
SRPaddr.mFields.m16[0] = 0xfff;
otIp6Address *SRPaddr_pointer = &SRPaddr;
otSrpClientService SRPclient;
SRPclient.mName = "_knx._udp";
SRPclient.mInstanceName = "fancy-service";
//SRPclient.mTxtEntries->mKey = NULL;
SRPclient.mPort = 12356;
SRPclient.mPriority = 1;
SRPclient.mWeight = 1;
SRPclient.mNumTxtEntries = 1;
otSrpClientService *SRPclient_pointer = &SRPclient;
otSrpClientSetHostName(sInstance, "SRPtest");
otSrpClientSetHostAddresses(sInstance,SRPaddr_pointer,0x0f);
otSrpClientAddService(sInstance, SRPclient_pointer);
otSrpClientStart(sInstance,SRP_1_pointer);
}
srp_client.h
#define OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 1
#define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE 1

TLS certificate verification failure

I need to have a code which performs 2-way authentication (client and server authenticates each other). My server is a TCP server. I intend to have TLS security added.
https://github.com/ospaarmann/exdgraph/wiki/TLS-client-authentication
I generated client and server, CA certificates and key files using the link above.
Server side code:
{
SSL_CTX_set_options(
ret,
SSL_OP_NO_SSLv2 |
SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION
);
SSL_CTX_set_verify(
ret,
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL
);
if (SSL_CTX_load_verify_locations(ret, NULL, "/home/ml5/tls_bio/MyRootCA.pem") == 0) {
fprintf(stderr, "Failed to load root certificates\n");
SSL_CTX_free(ret);
return NULL;
}
/*
* We won't set any verification settings this time. Instead
* we need to give OpenSSL our certificate and private key.
*/
if (SSL_CTX_use_certificate_chain_file(ret, "MyServer.pem") != 1) {
ssl_perror("SSL_CTX_use_certificate_file");
SSL_CTX_free(ret);
return NULL;
}
if (SSL_CTX_use_PrivateKey_file(ret, "MyServer.key", SSL_FILETYPE_PEM) != 1) {
ssl_perror("SSL_CTX_use_PrivateKey_file");
SSL_CTX_free(ret);
return NULL;
}
printf("Loaded root certificates\n");
/*
* Check that the certificate (public key) and private key match.
*/
if (SSL_CTX_check_private_key(ret) != 1) {
fprintf(stderr, "certificate and private key do not match!\n");
SSL_CTX_free(ret);
return NULL;
}
}
client side code:
=======================================================================
SSL_CTX *ret;
/* create a new SSL context */
ret = SSL_CTX_new(SSLv23_client_method( ));
if (ret == NULL) {
fprintf(stderr, "SSL_CTX_new failed!\n");
return NULL;
}
/*
* set our desired options
*
* We don't want to talk to old SSLv2 or SSLv3 servers because
* these protocols have security issues that could lead to the
* connection being compromised.
*
* Return value is the new set of options after adding these
* (we don't care).
*/
SSL_CTX_set_options(
ret,
SSL_OP_NO_SSLv2 |
SSL_OP_NO_SSLv3 |
SSL_OP_NO_COMPRESSION
);
/*
* set up certificate verification
*
* We want the verification to fail if the peer doesn't
* offer any certificate. Otherwise it's easy to impersonate
* a legitimate server just by offering no certificate.
*
* No error checking, not because I'm being sloppy, but because
* these functions don't return error information.
*/
SSL_CTX_set_verify(
ret,
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL
);
SSL_CTX_set_verify_depth(ret, 4);
/*
* Point our context at the root certificates.
* This may vary depending on your system.
*/
if (SSL_CTX_load_verify_locations(ret, NULL, "/home/ml5/tls_bio_l1/MyRootCA.pem") == 0) {
fprintf(stderr, "Failed to load root certificates\n");
SSL_CTX_free(ret);
return NULL;
}
/*
* We won't set any verification settings this time. Instead
* we need to give OpenSSL our certificate and private key.
*/
if (SSL_CTX_use_certificate_chain_file(ret, "MyClient.pem") != 1) {
SSL_CTX_free(ret);
return NULL;
}
if (SSL_CTX_use_PrivateKey_file(ret, "MyClient.key", SSL_FILETYPE_PEM) != 1) {
SSL_CTX_free(ret);
return NULL;
}
printf("Loaded root certificates\n");
/*
* Check that the certificate (public key) and private key match.
*/
if (SSL_CTX_check_private_key(ret) != 1) {
fprintf(stderr, "certificate and private key do not match!\n");
SSL_CTX_free(ret);
return NULL;
}
I am unsure what is wrong because of which when I start the server and the client,
I get the error as shown below on the client side:
BIO_do_connect failed: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
If I have my own verify callback on client and server ofcourse the 2-way authentication succeeds
SSL_CTX_set_cert_verify_callback(ctx, always_true_callback, NULL);
But I think thats not how it is to be done. Any help in this regard to solve the error shown above, will be greatly appreciated.
Just to those who come-in here. The issue was relating to how I generated CA certificate, client/server certificates. Once I corrected those, it started working.

Verifying my self-signed certificate with openSSL

I own the server and I own the customer's executable. I'd like to establish a secure TLS connection between them.
I can embed whatever I want into the client executable but I'm not sure how to validate a self-assigned certificate that my client received from a connection to the server, i.e. from a SSL_get_peer_certificate call.
I read around that certificates are just public keys with metadata parts signed with the private key. Can I somehow verify that the certificate the server sent me has indeed all the metadata correctly signed by embedding the public key into my client application? Is this possible (and if it is, how?)
I'm not sure how to validate a self-assigned certificate that my client received from a connection to the server ...
Depending on the OpenSSL library you are using, you have to perform two or three steps for verification. The two versions bisect at OpenSSL 1.1.0. OpenSSL 1.1.0 and above performs hostname validation so it only takes two steps. OpenSSL 1.0.2 and below does not perform hostname validation so it requires three steps.
The steps detailed below are from SSL/TLS Client on the OpenSSL wiki.
Server Certificate
Both OpenSSL 1.0.2 and 1.1.0 require you to check for the presence of a certificate. If you use ADH (Anonymous Diffie-Hellman), TLS-PSK (Preshared Key), TLS_SRP (Secure Remote Password), then there may not be a server certificate to verify.
You get the server's certificate with SSL_get_peer_certificate. If it returns non-NULL, then a certificate is present. Lack of a certificate may or may not be a reason to fail.
Certificate Chain
Both OpenSSL 1.0.2 and 1.1.0 require you to check the result of chain validation. Chain validation is part of path building, and its detailed in RFC 4158, Certification Path Building.
You get the result of path validation with SSL_get_verify_result.
Certificate Names
OpenSSL 1.0.2 an below requires you to verify the hostname matches a name listed in the certificate. Its a big topic, but the short of it is: any hostname or dns name needs to be present in the certifcate's Subject Alternative Name (SAN), and not the Common Name (CN). Also see How do you sign Certificate Signing Request with your Certification Authority and How to create a self-signed certificate with openssl? It provides a lot of background information on X.509 server certificates, how to present names, and where the various rules come from.
Effectively, you fetch the SANs with X509_get_ext_d2i(cert, NID_subject_alt_name, ...). Then you loop over the list and extract each name with sk_GENERAL_NAME_num. Then, you extract a GENERAL_NAME entry and ASN1_STRING_to_UTF8, and see if it matches the name you tried to connect to.
Below are the routines for printing the Subject Alternative Name (SAN) and the Common Name (CN). It came from the example on the OpenSSL wiki page.
void print_san_name(const char* label, X509* const cert)
{
int success = 0;
GENERAL_NAMES* names = NULL;
unsigned char* utf8 = NULL;
do
{
if(!cert) break; /* failed */
names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0 );
if(!names) break;
int i = 0, count = sk_GENERAL_NAME_num(names);
if(!count) break; /* failed */
for( i = 0; i < count; ++i )
{
GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
if(!entry) continue;
if(GEN_DNS == entry->type)
{
int len1 = 0, len2 = -1;
len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
if(utf8) {
len2 = (int)strlen((const char*)utf8);
}
if(len1 != len2) {
fprintf(stderr, " Strlen and ASN1_STRING size do not match (embedded null?): %d vs %d\n", len2, len1);
}
/* If there's a problem with string lengths, then */
/* we skip the candidate and move on to the next. */
/* Another policy would be to fails since it probably */
/* indicates the client is under attack. */
if(utf8 && len1 && len2 && (len1 == len2)) {
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
}
if(utf8) {
OPENSSL_free(utf8), utf8 = NULL;
}
}
else
{
fprintf(stderr, " Unknown GENERAL_NAME type: %d\n", entry->type);
}
}
} while (0);
if(names)
GENERAL_NAMES_free(names);
if(utf8)
OPENSSL_free(utf8);
if(!success)
fprintf(stdout, " %s: <not available>\n", label);
}
void print_cn_name(const char* label, X509_NAME* const name)
{
int idx = -1, success = 0;
unsigned char *utf8 = NULL;
do
{
if(!name) break; /* failed */
idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
if(!(idx > -1)) break; /* failed */
X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
if(!entry) break; /* failed */
ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
if(!data) break; /* failed */
int length = ASN1_STRING_to_UTF8(&utf8, data);
if(!utf8 || !(length > 0)) break; /* failed */
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
} while (0);
if(utf8)
OPENSSL_free(utf8);
if(!success)
fprintf(stdout, " %s: <not available>\n", label);
}
Verifying my self-signed certificate with openSSL
Because its your self-signed certificate, you can do even better than above. You have a priori knowledge of the host's public key. You can pin the public key, and just use the certificate to deliever the public key or as a presentation detail.
To pin the public key, see Public Key Pinning over at OWASP.
You should also avoid the IETF's RFC 7469, Public Key Pinning Extension for HTTP with Overrides. The IETF's rendition allows the attacker to break a known good pinset so the attacker can MitM the connection. They also suppress reporting the problem, so the user agent becomes complicit in the coverup.

Rolling my own SSL with OpenSSL, not working

I've read all the caveats about not doing this, but ... I need to. I need to be able to POST messages to an SSL/TLS secured server from a C program, and it's just not working.
I cat GET data via SSL using this same code, but I cannot POST. Every attempt returns a 400 BAD REQUEST. I can use the exact same data via another ReST client (oddly enough called "Rest Client") and it works. I can run the same command via curl and it works. But via C/openssl, same response.
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
/* https://www.openssl.org/docs/ssl/SSL_CTX_new.html */
const SSL_METHOD* method = SSLv23_method();
/* http://www.openssl.org/docs/ssl/ctx_new.html */
ctx = SSL_CTX_new(method);
/* https://www.openssl.org/docs/ssl/ctx_set_verify.html */
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
/* https://www.openssl.org/docs/ssl/ctx_set_verify.html */
SSL_CTX_set_verify_depth(ctx, 5);
const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
long old_opts = SSL_CTX_set_options(ctx, flags);
UNUSED(old_opts);
/* http://www.openssl.org/docs/ssl/SSL_CTX_set_default_verify_paths.html */
res = SSL_CTX_set_default_verify_paths(ctx);
/* https://www.openssl.org/docs/crypto/BIO_f_ssl.html */
web = BIO_new_ssl_connect(ctx);
/* https://www.openssl.org/docs/crypto/BIO_s_connect.html */
res = BIO_set_conn_hostname(web, HOST_NAME ":" HOST_PORT);
/* https://www.openssl.org/docs/crypto/BIO_f_ssl.html */
/* This copies an internal pointer. No need to free. */
BIO_get_ssl(web, &ssl);
/* https://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_PROTOCOL_CONTEXTS */
/* https://www.openssl.org/docs/ssl/SSL_CTX_set_cipher_list.html */
res = SSL_set_cipher_list(ssl, PREFERRED_CIPHERS);
/* No documentation. See the source code for tls.h and s_client.c */
res = SSL_set_tlsext_host_name(ssl, HOST_NAME);
/* https://www.openssl.org/docs/crypto/BIO_s_file.html */
out = BIO_new_fp(stdout, BIO_NOCLOSE);
/* https://www.openssl.org/docs/crypto/BIO_s_connect.html */
res = BIO_do_connect(web);
/* https://www.openssl.org/docs/crypto/BIO_f_ssl.html */
res = BIO_do_handshake(web);
/* Step 1: verify a server certifcate was presented during negotiation */
/* https://www.openssl.org/docs/ssl/SSL_get_peer_certificate.html */
X509* cert = SSL_get_peer_certificate(ssl);
/* Step 2: verify the result of chain verifcation */
/* http://www.openssl.org/docs/ssl/SSL_get_verify_result.html */
/* Error codes: http://www.openssl.org/docs/apps/verify.html */
res = SSL_get_verify_result(ssl);
certname = X509_NAME_new();
certname = X509_get_subject_name(cert);
BIO_printf(out, "Displaying the certificate subject data:\n");
X509_NAME_print_ex(out, certname, 0, 0);
BIO_printf(out, "\n");
sprintf(message, "POST /api/buckets\r\nHTTP/1.1\r\nX-IS-AccessKey: accessKey\r\nContent-Type: application/json\r\nContent-Length: 66\r\n\r\n{\"bucketKey\": \"MyBucket\", \"bucketName\": \"My Bucket\"}\r\n\r\n");
BIO_puts(web, message);
BIO_puts(out, message);
int len = 0;
do {
char buff[1536] = {};
/* https://www.openssl.org/docs/crypto/BIO_read.html */
len = BIO_read(web, buff, sizeof(buff));
if(len > 0)
BIO_write(out, buff, len);
/* BIO_should_retry returns TRUE unless there's an */
/* error. We expect an error when the server */
/* provides the response and closes the connection. */
} while (len > 0 || BIO_should_retry(web));
ret = 0;
} while (0);
And indeed this does successfully open a connection, and retrieve a certificate, and validate it, etc.
verify_callback (depth=1)(preverify=0)
Issuer (cn): DigiCert Global Root CA
Subject (cn): DigiCert SHA2 Secure Server CA
Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
verify_callback (depth=0)(preverify=1)
Issuer (cn): DigiCert SHA2 Secure Server CA
Subject (cn): *.initialstate.com
Subject (san): *.initialstate.com
Subject (san): initialstate.com
Displaying the certificate subject data:
C=US, ST=TN, L=Brentwood, O=Initial State Technologies, Inc, CN=*.initialstate.com
So that seems to work. And if I do a simple "GET /" from www.google.com I get the same certificate responses (well, with the appropriate certificate from google) and I get all the data back just fine.
So it seems to be something to do with actually POSTing data.
If anyone can point out the error of my ways -- not just my folly for doing this! -- I'de be very thankful!
..."POST /api/buckets\r\nHTTP/1.1\r\n
The newline between the path and the HTTP version is wrong and must be a space. This means that you send here
POST /api/buckets
HTTP/1.1
instead of
POST /api/buckets HTTP/1.1

How to read client certificate in polarssl?

How to read client certificate from server side using mbedtls(polarssl)?
I had a server that was coded using mbedtls(polarssl). I want to read the client certificate and fetch some information from that certificate. Can anyone know what function will be used to read client certificate?
I think you could use mbedtls_x509_crt_info which returns an informational string about the certificate.
You can get the peer certificate from the ssl session when the client connects and then print the info out.
mbedtls_ssl_context ssl;
...
mbedtls_x509_crt *crt = ssl.session->peer_cert;
unsigned char buf[1024];
int ret = mbedtls_x509_crt_info((char *) buf, sizeof( buf ) - 1, "", crt);
if( ret != -1 )
{
mbedtls_printf( "%s\n", buf );
}
I didn't test this, just checked the examples.