Obtaining ssl certificate on windows using C++ - c++

I am trying to obtain a remote server's ssl certificate on windows. One option I have found is to use openssl. The command to do that as indicated by some posts on the internet is:
openssl.exe s_client -showcerts -connect {REMOTE_SERVER_IP}:{REMOTE_SERVER_PORT}
This works perfectly, but my problem is that the above command has a timeout of 300 seconds. The certificate itself gets printed pretty fast and I see no reason to wait 300 seconds when I get all I want in the first few seconds. Still I think there is no way to change the timeout parameter on s_client. So I tried to figure a way to kill a process on windows after a given period of time but again had no luck there. Any ideas on how can this be done? If there is some other windows way to a obtain a remote servers ssl certificate and store it in a file this will also do the job.
EDIT: as per Bruno's request adding more information.
I am trying to create a c++ application that gets the SSL certificate of a remote server and stores it in a file for further processing. As my application already makes use of openssl.exe I either need a solution that uses openssl.exe or a standard windows command(i.e. does not require any additional libraries).
EDIT2: I have found a way to avoid the waiting in linux - just create an empty file and redirect the input of openssl s_client to it(or use pipe to pass empty input). This works on windows as well but with older versions of openssl(0.9.8l). I tried it with 0.9.8r and with 1.0.1b and redirecting the input to an empty file does not help there.

Here is a minimalistic program I created that connects to a server and prints its ssl certificate to the standard output. Hope it will help someone else to resolve similar issue:
#ifdef WIN32
#include <windows.h>
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif
#include <openssl/ssl.h>
#include <cstdlib>
#include <iostream>
static const char *host= "10.23.10.12";
static int port=443;
int tcp_connect(const char *host,int port)
{
#ifdef WIN32
WSADATA wsaData;
WORD version;
int error;
version = MAKEWORD( 2, 0 );
error = WSAStartup( version, &wsaData );
/* check for error */
if ( error != 0 )
{
/* error occured */
return -1;
}
/* check for correct version */
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 0 )
{
/* incorrect WinSock version */
WSACleanup();
return -1;
}
/* WinSock has been initialized */
#endif
struct hostent *hp;
struct sockaddr_in addr;
int sock;
if(!(hp=gethostbyname(host)))
printf("Couldn't resolve host");
memset(&addr,0,sizeof(addr));
addr.sin_addr=*(struct in_addr*)
hp->h_addr_list[0];
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
if((sock=(int)socket(AF_INET,SOCK_STREAM,
IPPROTO_TCP))<0)
printf("Couldn't create socket");
if(connect(sock,(struct sockaddr *)&addr,
sizeof(addr))<0)
printf("Couldn't connect socket");
return sock;
}
int main(int argc,char **argv)
{
SSL_CTX *ctx;
SSL *ssl;
BIO *sbio;
int sock;
SSL_METHOD *meth=NULL;
meth=SSLv23_client_method();
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
ctx=SSL_CTX_new(meth);
/* Connect the TCP socket*/
sock=tcp_connect(host,port);
/* Connect the SSL socket */
ssl=SSL_new(ctx);
sbio=BIO_new_socket(sock,BIO_NOCLOSE);
SSL_set_bio(ssl,sbio,sbio);
if(SSL_connect(ssl)<=0)
printf("SSL connect error");
X509 *peer;
peer=SSL_get_peer_certificate(ssl);
PEM_write_X509(stdout, peer);
SSL_CTX_free(ctx);
close(sock);
#ifdef WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
exit(0);
}
The code is modified version of the examples found here as suggested by this post.
EDIT: I kept getting the error OPENSSL_UPLINK: no OPENSSL_APPLINK on windows. After a lot of searching around the internet I found this post and added this to my code:
extern "C" {
#include <openssl/applink.c>
}
Seems this is some work around to avoid the requirement for compiler and run-time options compatibility.

Related

What information can I get from a socket connected to a server using c++ and windows?

I have a server and when a client connects to the server, I want to take all the information from the client and make a struct with it.
What information can I get?
I know that I can get the ipv4 and port from the client, there is anything left that I can get?
This is a short way of doing it:
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT 32406
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
sockaddr_in hint;
hint.sin_addr.S_un.S_addr = INADDR_ANY;
hint.sin_port = htons(DEFAULT_PORT);
hint.sin_family = AF_INET;
SOCKET listeningSocket = socket(AF_INET, SOCK_STREAM, 0);
bind(listeningSocket, (sockaddr*)&hint, sizeof(sockaddr_in));
listen(listeningSocket, SOMAXCONN);
sockaddr_in socketInfo;
int socketInfoLen = sizeof(socketInfo);
SOCKET clientSocket = accept(listeningSocket, (sockaddr*)&socketInfo, &socketInfoLen);
std::cout << inet_ntoa(socketInfo.sin_addr) << std::endl;
std::cout << socketInfo.sin_port << std::endl;
shutdown(clientSocket, SD_BOTH);
closesocket(clientSocket);
closesocket(listeningSocket);
WSACleanup();
return 0;
}
There is a whole lot of information available from getsockopt. It is a superset of what the other answer claims, for example
SO_BSP_STATE Returns the local address, local port, remote address, remote port, socket type, and protocol used by a socket.
Since you have a TCP socket you will be particularly interested in
IPPROTO_TCP socket options
There is different information available through WSAIoctl, for example
TCP_INFO_v1 structure
Some of these details will be local socket options (such as blocking or non-blocking), others will relate to the connection itself (e.g. negotiated window size). Some information about the remote client will be revealed, although not as much as if you used a bespoke fingerprinting tool.
Here is the implementation of #Ben Voigt's answer, if someone needs it:
#include <WinSock2.h>
#pragma comment (lib, "Ws2_32.lib")
bool GetSocketState(SOCKET sock, CSADDR_INFO& state) {
union CSADDR_INFO_PADDED {
CSADDR_INFO csaddr;
TCHAR padding[128];
} csaddrPadded {};
int infoLen = sizeof(csaddrPadded);
if (getsockopt(sock, SOL_SOCKET, SO_BSP_STATE, (TCHAR*)&csaddrPadded, &infoLen)) {
return false;
}
state = csaddrPadded.csaddr;
return true;
}
The only information you get that the client doesn't explicitly send is the sockaddr_in structure, ie the port and source IP address. Though of course you only get this when the client initiates a transfer (sends a packet with UDP or connects with TCP).
To get anything else, the client needs to send it as part of regular communication.

cpp connect() function is blocked indefinitely

#include <sys/socket.h>
#include <cstdio>
#include <stdlib.h>
#include <iostream>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#define BUFSIZE 5000
#define PORT 80
using namespace std;
int main(int argc, char* argv[]){
char buffer[BUFSIZE];
int sockfd;
struct sockaddr_in their_addr;
if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
perror("Socket generating failed");
exit(1);
}
their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(PORT);
their_addr.sin_addr.s_addr = htonl(((struct in_addr*)gethostbyname("www.google.com")->h_addr_list[0])->s_addr);
if(connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr)) == -1){ // stops at here!
perror("Connection failed");
exit(1);
}
close(sockfd);
return 0;
As a test of a combination of gethostbyname + connect, I wrote a simple code.
It queries the IP address of google by means of gethostbyname(), connects to google do nothing, and close the socket.
However, the program just stops at a line of the connect() function without any error including perror().
How can I fix this?
Get the s_addr, make sure it is an ipv4 address, and then on the command line try to ping that address with the command 'ping addr'
After that you could try a program like nmap but most likely ping will be enough.
There is probably nothing wrong with your code. You need to see if there is a proxy or firewall or anything else interfering with your network connection. You will also want to confirm you are getting an ipv4 address with gethostbyname
I solved this problem by removing htonl. I don't know why, and what could happen in future as a result of removing it. But this would be my best.
The socket API is not part of C++, it is posix. gethostbyname()is obsolete, use getaddrinfo instead. Read the appropriate man page, it also contains as example precisely the code you look for...

Asio UDP socket receive failed

Tried this code to send/receive with Asio UDP sockets (boost less version)
asio::io_service service;
asio::ip::udp::socket sock(service);
asio::ip::udp::endpoint endpoint(asio::ip::address::from_string("127.0.0.1"), 20100);
sock.connect(endpoint);
sock.send(buffer("testing\n"));
std::string buffer;
size_t length = sock.receive(asio::buffer(buffer)); <--- spawn exception
but got following error:
An existing connection was forcibly closed by the remote host
Something wrong here? Thanks for any help!
I don't know how you build your udp server, but I guess something wrong with it. I write an example program to explain the error message you get:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
struct sockaddr_in addr;
int fd, cnt, ret;
if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("error");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
addr.sin_port=htons(9090); // address which is not bound
ret = connect(fd,(struct sockaddr *)&addr,sizeof(addr));
char buf[512];
cnt = send(fd, "hello", sizeof("hello"), 0);
if(cnt < 0)
perror("send:");
cnt = recv(fd, buf, 512, 0); // error: Connection refused
if(cnt < 0)
perror("recv:");
return 0;
}
I try to send data to udp port 9090 at localhost or any host which no udp socket is bound to port 9090. the send() succeeds but the recv() fails. According to man page for udp:
All fatal errors will be passed to the
user as an error return even when the
socket is not connected. This includes
asynchronous errors received from the
network. You may get an error for an
earlier packet that was sent on the
same socket. This behaviour differs
from many other BSD socket
implementations which don't pass any
errors unless the socket is connected.
Linux's behaviour is mandated by
According to the rfc 1122
which says:
UDP MUST pass to the application layer all ICMP error messages that it receives from the IP layer. Conceptually at least, this may be accomplished with an upcall to the ERROR_REPORT routine
the send() succeeds, but it causes an ICMP error message(you can see it with tcpdump), then recv() sees this error(You may get an error for an earlier packet that was sent on the same socket), so it fails.

POP3 server - basic client operations in raw C++

I've spent at least 2 last hours searching for a way to make a simple connection to a POP3 server and get the number of messages waiting on it. As it's childlish-easy in C# and seems pretty basic in C++ on linux, I just can't find even the slightest tutorial on how to make it work on Windows.
I don't want to use any third-party libraries - i just want to code a simple console program, using raw C++ only, just to do some basic stuff as described above. All the sources I've tried to study are like:
POP3 is a protocol that has somethng to do with emails and it's very simple. Now let's proceed to writing a multi-platform POP3 server-client application, using a F16 fighter jet and inventing a time machine in progress.
I just can't seem to find any SIMPLE solutions...
I've written (with some help) a simple snippet that SHOULD work on linux - at least according to the tutorials; I have no means to check it right now.
Hovewer, the C++ is not my "native language" and when I try to transfer it into Windows, I just fall from one hole into the other and have to spend yet another quarter of an hour GGoogle'ing the solution.
At this point, the code is compiling, but the linker fails. It's strange, because I've added the ws2_32.lib to the linker, so it SHOULD work just fine. In return, I only get loads of LNK2019.
Can you please help me with the code or provide any link to a SIMPLE solution that works on Windows?
The code:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <winsock2.h>
#include <windows.h>
#else
#endif
#ifndef in_addr_t
#define in_addr_t long
#endif
#include <string.h>
void err(char *where) {
fprintf(stderr, "error in %s: %d\n", where, errno);
exit(1);
}
int main(int argc, char *argv[]) {
char *remote = "some_address";
struct servent *sent;
struct protoent *pent;
int port;
int sock;
int result;
in_addr_t ipadr;
struct sockaddr_in addr;
struct hostent *hent;
char buf[2048];
sent = getservbyname("http", "pop3");
if(sent == NULL)
err("getservbyname");
port = sent->s_port;
pent = getprotobyname("pop3");
if(pent == NULL)
err("getprotobyname");
hent = gethostbyname(remote);
printf("Host: %s\n", hent->h_name);
printf("IP: %s\n", inet_ntoa(*((struct in_addr *)hent->h_addr)));
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr = *((struct in_addr *)hent->h_addr);
memset(addr.sin_zero, '\0', 8);
sock = socket(AF_INET, SOCK_STREAM, pent->p_proto);
if(sock < 0)
err("socket");
result = connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr));
if(result < 0)
err("connect");
}
You have to add WSAStartup before you use any Winsock function. When you are done, you have to call WSACleanup.
Example(from msdn):
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
return 1;
}
//Do stuf here
WSACleanup();

Creating a basic C/C++ TCP socket writer

Below is the following basic socket code I came up with:
//General includes:
#include <iostream>
#include <stdio.h>
#include <string>
//Network related includes:
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
//Target host details:
#define PORT 1234
#define HOST "74.74.74.74"
using namespace std;
//Function prototypes:
string MessageFormat(int, char**);
void MessageSend(string);
int main(int argc, char *argv[])
{
//Parse arguments and format message:
string message = MessageFormat(argc, argv);
//Send the message out:
MessageSend(message);
return 0;
}
string MessageFormat(int argc, char *argv[])
{
//Massage the command line parameters
// into my desired payload format.
return message;
}
void MessageSend(string message)
{
int sd, ret;
struct sockaddr_in server;
struct in_addr ipv4addr;
struct hostent *hp;
sd = socket(AF_INET,SOCK_DGRAM,0);
server.sin_family = AF_INET;
inet_pton(AF_INET, HOST, &ipv4addr);
hp = gethostbyaddr(&ipv4addr, sizeof ipv4addr, AF_INET);
//hp = gethostbyname(HOST);
bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
server.sin_port = htons(PORT);
connect(sd, (const sockaddr *)&server, sizeof(server));
send(sd, (char *)message.c_str(), strlen((char *)message.c_str()), 0);
}
This is quite basic, and does in fact work. HOWEVER, it's sending UDP packets instead of TCP packets, so the target host expecting TCP rejects these. Also, by inspecting connect/send values and watching my interfaces with ngrep I can 100% verify the packet is going out, so that's not the issue.
I'm only interested in modifying what I have, not creating a full featured server with boost asio. How can I tweak this so that it operates in terms of TCP instead of UDP?
Following are changes you need to make to transfer data via TCP
While creating socket pass correct parameters .In above example you passed SOCK_DGRAM instead pass SOCK_STREAM.
After binding server should go into listen mode (check the manual page of listen)
while Client Side should connect after socket creation.
Then accept in server side after listen.
Final Read and write to transfer data
Diagram attached will give you a clear picture of TCP connection
You can check manual pages for detailed info on all functions or refer beej's guide for socket programming ( use this link )
Replace SOCK_DGRAM with SOCK_STREAM.
Also, read the manual or get a good book.