How to implement SNI using openssl configuration file? - c++

I have implemented SNI using OpenSSL but not using an OpenSSL config file (cnf). I am loading a server SSL_CTX doing the following:
FILE *fp;
CONF *cnf = NULL;
long eline;
fp = fopen("/somepath/app.cnf", "r");
if (fp == NULL) {
fprintf(stderr, "Error opening configuration file\n");
/* Other missing configuration file behaviour */
} else {
cnf = NCONF_new(NULL);
if (NCONF_load_fp(cnf, fp, &eline) == 0) {
fprintf(stderr, "Error on line %ld of configuration file\n", eline);
ERR_print_errors_fp(stderr);
/* Other malformed configuration file behaviour */
} else if (CONF_modules_load(cnf, "appname", 0) <= 0) {
fprintf(stderr, "Error configuring application\n");
ERR_print_errors_fp(stderr);
/* Other configuration error behaviour */
}
fclose(fp);
NCONF_free(cnf);
}
It works fine, but now I am trying to implement server-side SNI using the OpenSSL config file and I don't know how can I get the required information to do it. I have taken a look to How to implement Server Name Indication (SNI) and this is a good explanation to do it without openssl config file. But that doesn't work using the file.
How can I determine if the server have the certificate requested? Maybe openssl provides the proper certificate by itself?

Related

Trying to make a secure handshake between server and client with OpenSSL

I'm trying to make a basic Client-Server program that can exchange messages using the OpenSSL library. I'm very new to OpenSSL and cryptography and I'm trying to understand exactly how to make sure that the connection between my client and server is secure. Currently I'm using self signed certificates for both client and server but the certificate verification fails when the client tries to connect to the server with this error:
140336190395008:error:1417C086:SSL routines:tls_process_client_certificate:certificate verify failed:../ssl/statem/statem_srvr.c:3711:
In the main method of my server program, I first set verify for the CTX and use the following flags:
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
Then when setting up the servlet I call the following method to show certificates:
void ShowCerts(SSL* ssl) /*show the ceritficates to client and match them*/ {
X509 *cert;
long int verify;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
verify = SSL_get_verify_result(ssl);
if (verify == X509_V_OK) {
printf("Yay it worked\n");
}
if ( cert != NULL ) {
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Server: %s\n", line); /*server certifcates*/
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("client: %s\n", line); /*client certificates*/
free(line);
X509_free(cert);
} else {
printf("No certificates.\n");
}
}
As I said I'm very new to this so I might be missing something basic here. Also apologies in advance if I missed any important info, this is my first time asking a question here.

export and import certificates chain

I try to export pfx file which contain certificates chain and private key from windows certificates store, convert oit into PEM format and save it to file which be read by openssl based application.
I do it by the following steps (capi / openssl commands):
creating memory store - CertOpenStore
Open system store - CertOpenSystemStore
find desired certificate according to freindly name -
CertFindCertificateInStore
Add desired certificate to memory store - CertAddCertificateContextToStore
export memory store - PFXExportCertStoreEx
convert blob into base64 and save into file
Import certificates chain from PEM file- SSL_CTX_use_certificate_chain_file
Import private key from PEM file - SSL_CTX_use_PrivateKey_file
1) I didn't find a command which convert pfx (memory blob / file) to pem format
2) does this scenario export all certificate chain which were originally store in the pfx file
3) does SSL_CTX_use_certificate_chain_file import all certificates chain or I have to use other commands to import all chain into CTX structure
Thanks in advance
1) This worked for me
{
FILE* fp = NULL;
CString errorS = NULL;
PKCS12* p12 = NULL;
EVP_PKEY* pkey = NULL;
X509* cert = NULL;
STACK_OF(X509) *ca = NULL;
int i;
pkey = (EVP_PKEY*)new EVP_PKEY;
cert = (X509*)new X509;
do
{
if (fopen_s(&fp, CT2A(pkcs12File), "rb"))
{
errorS = ("Error opening file %s\n", CT2A(pkcs12File));
break;
}
p12 = d2i_PKCS12_fp(fp, NULL);
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
if (!p12)
{
errorS = ("Error reading PKCS#12 file\n");
break;
}
if (!PKCS12_parse(p12, CT2A(szPassword), &pkey, &cert, &ca))
{
errorS = ("Error parsing PKCS#12 file\n");
break;
}
if (fopen_s(&fp, CT2A(pszNameString + L".pem"), "w"))
{
errorS = ("Error opening file %s\n", CT2A(pemFileName));
break;
}
if (pkey)
{
fprintf(fp, "***Private Key***\n");
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
}
if (cert)
{
fprintf(fp, "***User Certificate***\n");
PEM_write_X509_AUX(fp, cert);
}
if (ca && sk_X509_num(ca))
{
fprintf(fp, "***Other Certificates***\n");
for (i = 0; i < sk_X509_num(ca); i++)
PEM_write_X509_AUX(fp, sk_X509_value(ca, i));
}
} while (0);
PKCS12_free(p12);
sk_X509_pop_free(ca, X509_free);
X509_free(cert);
EVP_PKEY_free(pkey);
if (NULL != fp)
{
fclose(fp);
}
}
2+3) SSL_CTX_use_certificate_chain_file import all certificates chain

gSOAP - How to use SSL and self-signed certificate

I need to connect my cross-platform program to a SOAP web service. I have compiled the gSOAP tools wsdl2h and soapcpp2 and with these tools I have generated the source code files from from the .wsdl file. I have putted in the stdsoap2.h the define "#define WITH_OPENSSL" and in this way SSL are used. The problem is that when i call the service the call return ERROR 30 that means SSL ERROR but i don't know what is really the problem. I know the server send a self-signed certificate because this is a testing environment. Indeed an error message related this is printed. The output is:
Creating SOAP objects ...
Calling SOAP httpAccessService:
SSL verify error or warning with certificate at depth 0: self signed certificate
certificate issuer /C=IT/ST=Milan/L=Milan/O=Company/OU=Company/CN=company.it
certificate subject /C=IT/ST=Milan/L=Milan/O=Company/OU=Company/CN=company.it
SOAP ERROR 30
The function i use to call the service is this:
void gSOAPTesting::runTest()
{
int result = 0;
size_t requestSize;
size_t responseSize;
char endpoint[1024];
char buffer[8192];
string SoapAction;
struct soap *soap_container;
ApplicationConfigurationServiceSoapBindingProxy Proxy1;
_ns1__httpAccessService *httpAccessService;
_ns1__httpAccessServiceResponse *httpAccessServiceResponse;
printf("Creating SOAP objects ...\n");
soap_container = soap_new();
//soap_container->mode
httpAccessService = (_ns1__httpAccessService *) soap_instantiate(soap_container , SOAP_TYPE___ns1__httpAccessService , "" , "" , &requestSize);
httpAccessServiceResponse = (_ns1__httpAccessServiceResponse *) soap_instantiate(soap_container , SOAP_TYPE___ns1__httpAccessService , "" , "" , &responseSize);
soap_ssl_init(); /* init OpenSSL (just once) */
if(soap_ssl_client_context(soap_container ,
SOAP_SSL_DEFAULT ,
NULL,
NULL,
NULL,
NULL,
NULL
) != SOAP_OK)
{
printf("SOAP SSL Initialization Failure\n");
soap_print_fault(soap_container , stderr);
return ;
}
printf("Calling SOAP httpAccessService:\n");
SoapAction.clear();
SoapAction.append(SOAP_NAMESPACE_OF_ns1);
SoapAction.append("/");
SoapAction.append("httpAccessService");
result = Proxy1.httpAccessService("https://XXX.XXX.XXX.XXX:XXXX" , NULL , httpAccessService , httpAccessServiceResponse);
if(result == SOAP_OK)
{
printf("SOAP OK\n");
}
else
{
printf("SOAP ERROR %d\n" , result);
if(soap_check_state(soap_container) ) printf("Error: request soap struct not initialized\n");
if(httpAccessService->soap == NULL)
{
printf("Error: NULL request SOAP struct\n");
return;
}
if(httpAccessService->soap->endpoint == NULL) printf("Error: Empty request endpoint\n");
soap_stream_fault(soap_container , std::cout);
}
}
Any help is appreciated.
The problem is related the certificate that is not trusted because is self-signed. If I comment these lines in stdsoap2.cpp...
if (!ok)
{ soap_set_sender_error(soap, "SSL/TLS error", "SSL/TLS certificate host name mismatch in tcp_connect()", SOAP_SSL_ERROR);
soap->fclosesocket(soap, sk);
return SOAP_INVALID_SOCKET;
}
...the certificate is accepted even if the it is issued by an unknown authority.
if (soap_ssl_client_context(&soap,
SOAP_SSL_NO_AUTHENTICATION,
NULL , NULL,
NULL, /* ````````````````````````````````*/
NULL,NULL )!= SOAP_OK)
{
If you are ok ignoring the host you can do something like above instead of commneting stuff in generated files

How to copy a file in C/C++ with libssh and SFTP

I want to copy a file from a client to a remote server, but I don't understand how to do it with the libssh library SFTP API.
The situation is that: The SSH session is open and the SFTP session is open too, I can create a file and write in it from the client to the server with the integrated function of libssh.
I did not find an easy way to copy a file from the client to the server with a simple function like sftp_transfer(sourceFile(like c:\my document\hello world.txt),RemoteFile(/home/user/hello world.txt),right(read and write)) ?
With what I have understood from the tutorial it is first creating a file in the remote location (server) then it is opening this file with this line of code:
file = sftp_open(sftp, "/home/helloworld.txt",access_type,1);
After that the file is created on the server, and then it is writing into this created file with a buffer:
const char *helloworld = "Hello, World!\n";
int length = strlen(helloworld);
nwritten = sftp_write(file, helloworld, length);
My question is now if I have a file for example a .doc file and I want to transfer/upload that file from c:\mydocument\document.doc to remote the remote server /home/user/document.doc, how can I do it with this method ?
How can I put this file into the sftp_write() function to send it like the helloworld in the sample function?
I may be not good enough in programming to understand, but I really tried to understand it and I'm stuck with it.
Thanks in advance for your help
See below a sample of the code I used to test:
// Set variable for the communication
char buffer[256];
unsigned int nbytes;
//create a file to send by SFTP
int access_type = O_WRONLY | O_CREAT | O_TRUNC;
const char *helloworld = "Hello, World!\n";
int length = strlen(helloworld);
//Open a SFTP session
sftp = sftp_new(my_ssh_session);
if (sftp == NULL)
{
fprintf(stderr, "Error allocating SFTP session: %s\n",
ssh_get_error(my_ssh_session));
return SSH_ERROR;
}
// Initialize the SFTP session
rc = sftp_init(sftp);
if (rc != SSH_OK)
{
fprintf(stderr, "Error initializing SFTP session: %s.\n",
sftp_get_error(sftp));
sftp_free(sftp);
return rc;
}
//Open the file into the remote side
file = sftp_open(sftp, "/home/helloworld.txt",access_type,1);
if (file == NULL)
{
fprintf(stderr, "Can't open file for writing: %s\n",ssh_get_error(my_ssh_session));
return SSH_ERROR;
}
//Write the file created with what's into the buffer
nwritten = sftp_write(file, helloworld, length);
if (nwritten != length)
{
fprintf(stderr, "Can't write data to file: %s\n",
ssh_get_error(my_ssh_session));
sftp_close(file);
return SSH_ERROR;
}
Open the file in the usual way (using C++'s fstream or C's stdio.h), read its contents to a buffer, and pass the buffer to sftp_write.
Something like this:
ifstream fin("file.doc", ios::binary);
if (fin) {
fin.seekg(0, ios::end);
ios::pos_type bufsize = fin.tellg(); // get file size in bytes
fin.seekg(0); // rewind to beginning of file
std::vector<char> buf(bufsize); // allocate buffer
fin.read(buf.data(), bufsize); // read file contents into buffer
sftp_write(file, buf.data(), bufsize); // write buffer to remote file
}
Note that this is a very simple implementation. You should probably open the remote file in append mode, then write the data in chunks instead of sending single huge blob of data.
The following example uses ifstream in a loop to avoid loading a whole file into a memory (what the accepted answer is doing):
ifstream fin("C:\\myfile.zip", ios::binary);
while (fin)
{
constexpr size_t max_xfer_buf_size = 10240
char buffer[max_xfer_buf_size];
fin.read(buffer, sizeof(buffer));
if (fin.gcount() > 0)
{
ssize_t nwritten = sftp_write(NULL, buffer, fin.gcount());
if (nwritten != fin.gcount())
{
fprintf(
stderr, "Error writing to file: %s\n", ssh_get_error(ssh_session));
sftp_close(file);
return 1;
}
}
}
I used followed the example here.
sftp_read_sync uses an infinite loop to read a file from a server into /path/to/profile
from server path /etc/profile.

gSoap + SSL : CRL & certificate name check

I'm developing a webservice using gSOAP with SSL support. It works fine as long as I COPY (that's it!) the code provided as gSOAP documentation. Trying to add some feature I collide with a lot of difficulties! I don't have a good knowledge of OpenSSL libraries, so I'm here to ask your help.
I should add a CRL list to check the certificate sent by the client. How can I do it? Moreover, I changed the function pointed by soap.fsslverify with this one:
int servlet_fsslverify(int ok, X509_STORE_CTX *store)
{
ok = 1;
char buf[1024];
X509 *cert = X509_STORE_CTX_get_current_cert(store);
fprintf(stderr, "SSL verify error or warning with certificate at depth %d: %s\n",
X509_STORE_CTX_get_error_depth(store),
X509_verify_cert_error_string(X509_STORE_CTX_get_error(store)));
X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
fprintf(stderr, "certificate issuer %s\n", buf);
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
fprintf(stderr, "certificate subject %s\n", buf);
/* Note: return 1 to continue, but unsafe progress will be terminated by OpenSSL */
return ok;
}
It is called everytime a client tries to authenticate. As you can see, I'm able to check the fields in client's certificate, but I really don't know how to check if the particular certificate is present or not in a CRL.
That's all, thanks a lot to everyone would be so nice to answer.
I found the solution on the internet! Sorry I don't remember where, but I'll try to find it back and I'll edit this post - credits to the solver.
Code to be inserted right after server-context creation.
X509_STORE *store;
store = SSL_CTX_get_cert_store(ServicePtr->ctx);
if (store)
{
X509_LOOKUP *lookup;
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
if (lookup)
{
if ( X509_load_crl_file(lookup, globals.pki_crl, X509_FILETYPE_ASN1) < 1 )
{
std::cerr << "CRL not found or invalid" << std::endl;
}
}
else
{
std::cerr << "Unable to create a valid lookup" << std::endl;
}
}
else
{
std::cerr << "Unable to get X509_STORE" << std::endl;
}