// Copyright (c) 2001  David Muse
// See the file COPYING for more information

#include <rudiments/inetclientsocket.h>
#include <rudiments/charstring.h>
#include <rudiments/error.h>

#include <openssl/err.h>

#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif

int passwdCallback(char *buf, int size, int rwflag, void *userdata) {
	charstring::copy(buf,(char *)userdata,size);
	buf[size-1]=(char)NULL;
	return charstring::length(buf);
}

int main(int argc, const char **argv) {

	// initialize the SSL context
	SSL_library_init();
	SSL_load_error_strings();

	// Create a new client context usng SSLv2.
	SSL_CTX	*ctx=SSL_CTX_new(SSLv2_client_method());

	// in cases where a re-negotiation must take place during an SSL_read
	// or SSL_write, automatically re-negotiate, then retry the read/write
	// instead of causing the read/write to fail
	SSL_CTX_set_mode(ctx,SSL_MODE_AUTO_RETRY);

	// load the client's certificate chain
	SSL_CTX_use_certificate_chain_file(ctx,"client.pem");

	// if the private key requires a password in order to read it,
	// supply "password"
	SSL_CTX_set_default_passwd_cb(ctx,passwdCallback);
	SSL_CTX_set_default_passwd_cb_userdata(ctx,(void *)"password");

	// load the client's private key
	SSL_CTX_use_PrivateKey_file(ctx,"client.pem",SSL_FILETYPE_PEM);

	// load certificates for the signing authorities that we trust
	SSL_CTX_load_verify_locations(ctx,"ca.pem",0);
	#if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
		// server certificates must be directly signed
		// by one of the signing authroities that we trust
		SSL_CTX_set_verify_depth(ctx,1);
	#endif

	// create an inet socket client
	inetclientsocket	clnt;
	clnt.setSSLContext(ctx);

	// connect to a server on localhost, listening on port 8000
	if (clnt.connect("localhost",8000,-1,-1,1,1)<0) {
		if (errno) {
			printf("connect failed: %s\n",error::getErrorString());
		} else {
			printf("connect failed: ");
			ERR_print_errors_fp(stdout);
			printf("\n");
		}
		clnt.close();
		exit(1);
	}

	// make sure the server sent a certificate
	X509	*certificate=SSL_get_peer_certificate(clnt.getSSL());
	if (!certificate) {
		printf("peer sent no certificate\n");
		clnt.close();
		exit(1);
	}

	// make sure the certificate was valid
	long	result=SSL_get_verify_result(clnt.getSSL());
	if (result!=X509_V_OK) {
		printf("SSL_get_verify_result failed: %d\n",result);
		clnt.close();
		exit(1);
	}

	// Make sure the commonname in the certificate is the one we expect it
	// to be (server.localdomain).
	// (we may also want to check the subject name field or certificate
	// extension for the commonname because sometimes it's there instead
	// of in the commonname field)
	char	commonname[256];
	X509_NAME_get_text_by_NID(X509_get_subject_name(certificate),
					NID_commonName,commonname,256);
	if (charstring::compareIgnoringCase(commonname,"server.localdomain")) {
		printf("%s!=server.localdomain\n",commonname);
		clnt.close();
		exit(1);
	}

	// write "hello" to the server
	clnt.write("hello",5);

	// read 10 bytes from the server and display them
	char	buffer[11];
	int	sizeread=clnt.read(buffer,10);
	buffer[sizeread]=(char)NULL;
	printf("%s\n",buffer);

	// close the connection to the server
	clnt.close();
}


syntax highlighted by Code2HTML, v. 0.9.1