
void
init_ctx ( void )
{
	/* Register the available ciphers and digests.
	 * [Note] This function must be called before any other action takes place. */
	SSL_library_init ();

	/* Register the error strings for all libcrypto functions as
	 * well as the libssl error strings. */
	SSL_load_error_strings ();

	/* Create a file BIO wrapping stderr. */
	{
		BIO *bio_err;
		bio_err = xBIO_new_fp ( stderr, BIO_NOCLOSE );
		init_bio_err ( bio_err );
	}

	/* Create our context. */
	{
		SSL_METHOD *meth;
		/* Constructor for the SSLv3 SSL_METHOD structure for combined client and server. */
		meth = SSLv3_method ();
		
		/* Create a new SSL_CTX object. 
		 * [Note] only understand the SSLv3 protocol. */
		ctx = xSSL_CTX_new ( meth );
	}


	/* Allow SSL_write(..., n) to return r with 0 < r < n
	 * (i.e. report success when just a single record has been
	 * written). */
	SSL_CTX_set_mode( ctx, SSL_MODE_ENABLE_PARTIAL_WRITE );

	xSSL_CTX_use_certificate_chain_file ( ctx, keyfile );
	
	/* Set the default password callback called when
	 * loading/storing a PEM certificate with encryption. */
	SSL_CTX_set_default_passwd_cb ( ctx, password_cb );


	/* Load the CAs we trust*/
	xSSL_CTX_use_PrivateKey_file (ctx, keyfile, SSL_FILETYPE_PEM);

	{
#if 0
		SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, 0);
		SSL_CTX_set_cert_verify_callback (ctx, verify_dont_fail_cb, NULL);
#endif

		xSSL_CTX_load_verify_locations ( ctx, CA_LIST, NULL );

		/* Set the maximum depth for the certificate chain
		 * verification that shall be allowed for <ctx>. */
		SSL_CTX_set_verify_depth ( ctx, 1 );


#if 0
		/* Set list of CAs sent to the client when requesting a client certificate */
		ph_SSL_CTX_set_client_CA_list (ctx, SSL_load_client_CA_file (ca_file));
#endif
	}
	
	/* Load randomness */
	xRAND_load_file ( RANDOM, -1 );

#if 0
	/* DH (Diffie-Hellman) */
	{
		DH * dhe1024 = NULL;
		int i;
		
		RAND_bytes ( (unsigned char *) &i, sizeof i);
		/* make sure that i is non-negative -- pick one of the provided
		 * seeds */
		if (i < 0) { i = -i; }
		if (i < 0) { i = 0; }
		dhe1024 = set_dhe1024 (i);
		assert (dhe1024 != NULL);
		
		ph_SSL_CTX_set_tmp_dh (ctx, dhe1024);
		
		// DH_free (dhe1024);

		/* avoid small subgroup attacks: */
		SSL_CTX_set_options (ctx, SSL_OP_SINGLE_DH_USE);
	}
#endif
}


void 
destroy_ctx ( void )
{
	/* Decrement the reference count of <ctx>, and removes the
	 * SSL_CTX object pointed to by <ctx> and frees up the
	 * allocated memory if the reference count has reached 0. */
	SSL_CTX_free (ctx);	
}


/* to hinder OpenSSL from asking for passphrases */
static int 
no_passphrase_callback(char *buf, int num, int w, void *arg) {
     return -1;
}


#if OPENSSL_VERSION_NUMBER >= 0x00907000L
static int
verify_dont_fail_cb(X509_STORE_CTX *c, void *unused_arg)
#else
static int
verify_dont_fail_cb(X509_STORE_CTX *c)
#endif
{
     int i;
    
     i = X509_verify_cert(c); /* sets c->error */
#if OPENSSL_VERSION_NUMBER >= 0x00905000L /* don't allow unverified
					   * certificates -- they could
					   * survive session reuse, but
					   * OpenSSL < 0.9.5-dev does not
					   * preserve their verify_result */
     if (i == 0)
	  return 1;
     else
#endif
	  return i;
}


/* ???? */
/* Check that the common name matches the host name*/
void
check_cert_chain ( SSL *ssl, char *host )
{
	X509 *peer;
	char peer_CN[256];
	
	/* Return the result of the verification of the X509
	 * certificate presented by the peer, if any. */
	if ( SSL_get_verify_result (ssl) != X509_V_OK )
		ssl_failure ("check_cert_chain");

	/*Check the cert chain. The chain length
	  is automatically checked by OpenSSL when we
	  set the verify depth in the ctx */
	
	/* Check the common name*/
	peer = SSL_get_peer_certificate ( ssl );

        int i;
        X509_NAME_ENTRY *e;

	/* Process all commonName entries: */

        int loc;


	X509_NAME *name = 509_get_subject_name (peer);

        loc = -1;
	for ( ;; ) {
		X509_NAME_ENTRY *e;

		loc = X509_NAME_get_index_by_NID( name, NID_commonName, loc );
		if (loc == -1)
			break;
		
		 e = X509_NAME_get_entry(nm, lastpos);
		/* Do something with <e> */


		 /*
		   xX509_NAME_get_text_by_NID ( name, NID_commonName, peer_CN, 256);
		   if (strcasecmp (peer_CN,host))
		   err_exit ("Common name doesn't match host name");
		 */
	}
}



void
load_dh_params ( SSL_CTX *ctx, char *file )
{
	DH *ret = 0;
	BIO *bio;

	bio = xBIO_new_file ( file, "r" );
	ret = PEM_read_bio_DHparams( bio, NULL, NULL, NULL ); /* unspecified. */
	BIO_free ( bio );
	xSSL_CTX_set_tmp_dh ( ctx, ret );
}

void
generate_eph_rsa_key ( SSL_CTX *ctx )
{
	RSA *rsa;
	
	rsa = xRSA_generate_key ( 512, RSA_F4, NULL, NULL );
	
	xSSL_CTX_set_tmp_rsa ( ctx, rsa );
		
	RSA_free(rsa);
}
    
int serv ()
{
	static int s_server_session_id_context = 1;

    /* Build our SSL context*/
    ctx=initialize_ctx(KEYFILE,PASSWORD);
    load_dh_params(ctx,DHFILE);
    generate_eph_rsa_key(ctx);
    
    SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,
      sizeof s_server_session_id_context);
    


}

SSL *
SSL_new_with_socket ( SSL_CTX *ctx, int sock )
{
	SSL *ssl;
	BIO *sbio;

	assert ( ctx != NULL );

	ssl = xSSL_new ( ctx );

	sbio = xBIO_new_socket ( sock, BIO_NOCLOSE );

	/* Connects the BIOs <sbio> for the read and write operations
	 * of the TLS/SSL (encrypted) side of <ssl>. */
	SSL_set_bio ( ssl, sbio, sbio );

	return ssl;
}




enum grid_error {
	NO_ERROR = 0
};

typedef enum grid_error		grid_error_t;

grid_error_t
grid_get_error () 
{
	return NO_ERROR;
}

void
grid_perror () 
{
	
}

void
grid_init_ssl ( )
{
	
}

void
grid_initialize ( )
{
	grid_read_config ();

	grid_init_ssl ();
}

void
grid_finalize ( )
{
	
}





int
main ( int argc, char *argv[] )
{

	init_ctx ();

	/* connect to the specifed host. */
	sock = tcp_connect ();

	/* Connect the SSL socket */
	ssl = xSSL_new ( ctx );

	sbio = BIO_new_socket ( sock, BIO_NOCLOSE );

	/* Connects the BIOs <sbio> for the read and write operations
	 * of the TLS/SSL  (encrypted) side of <ssl>. */
	SSL_set_bio ( ssl, sbio, sbio );

	ret = SSL_connect ( ssl );

	check_cert_chain ( ssl, HOST );


	/* send/receive */

	destroy_ctx ();

	printf ( "ok.\n" );	
	
	return 0;
}
