On Thu, 16 Mar 2000, Lutz Jaenicke wrote:
Thanks to everybody helping me. As I understand it the process is:
In s_server.c s_server_verify is set to
SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE for the case I am interested in.
Then it calls SSL_CTX_load_verify_locations(ctx,CAfile,CApath)
or SSL_CTX_set_default_verify_paths(ctx)
and SSL_CTX_set_verify(ctx,s_server_verify,verify_callback).
I've added the following lines to serv.cpp:
SSL_CTX_set_default_verify_paths(ctx);
SSL_CTX_set_verify( ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, NULL );
and the error it returns on failing is:
Connection from 100007f, port f04
4294401037:error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no
certificate returned:d:\work\openssl\openss~1.5\ssl\s3_srvr.c:1677:
I'm using openssl.exe with the command line "openssl s_client -connect
localhost:443 -key z:\robert.key -cert z:\robert.crt" to test the server
program.
If I use openssl.exe as server, everything seems to work. The command line
I use is: "d:\work\openssl\bin>openssl.exe s_server -key z:\robert.key
-cert z:\robert.crt -accept 443 -verify 1".
Attached is the file I'm playing with.. A modified version of serv.cpp for
Borland C++ Builder 4.0.
Any ideas would really be apreciated.
Robert Sandilands
> From: Lutz Jaenicke <[EMAIL PROTECTED]>
> Subject: Re: demos/ssl/serv.cpp
>
> On Thu, Mar 16, 2000 at 11:19:16AM +0200, [EMAIL PROTECTED] wrote:
> > On Wed, 15 Mar 2000, Wade L. Scholine wrote:
> > > From: Wade L. Scholine <[EMAIL PROTECTED]>
> > > To: "'[EMAIL PROTECTED]'" <[EMAIL PROTECTED]>
> > > Subject: RE: demos/ssl/serv.cpp
> >
> > client_cert = SSL_get_certificate( ssl );
> >
> > in serv.cpp always fails. I want to know how can I make that one line
> > work?
>
> Again, Wade already gave you the necessary answer. The client will only
> send the certificate to the server, _if_ explicitely asked to do so
> during handshake. The default is to not ask for a client certificate.
> On the server you must change the behaviour with the
> SSL_[CTX_]set_verify() call and the options SSL_VERIFY_PEER etc options.
> Please check apps/s_server.c as an example on how the call is used and
> grep for s_server_verify to see the setting of the options.
>
> Only then you can later access the client certificate. Or to say it the
> other way round, without setting the verify option, this example should
> never have shown a client certificate to anybody.
#pragma hdrstop
#include <condefs.h>
//---------------------------------------------------------------------------
USELIB("..\..\openssl\lib\ssleay32.lib");
USELIB("..\..\openssl\lib\libeay32.lib");
//---------------------------------------------------------------------------
/* serv.cpp - Minimal ssleay server for Unix
30.9.1996, Sampo Kellomaki <[EMAIL PROTECTED]> */
/* mangled to work with SSLeay-0.9.0b and OpenSSL 0.9.2b
Simplified to be even more minimal
12/98 - 4/99 Wade Scholine <[EMAIL PROTECTED]> */
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#ifndef __WIN32__
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#else
#include <windows.h>
#endif
#include <openssl/rsa.h> /* SSLeay stuff */
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
/* define HOME to be dir for key and cert files... */
#ifdef __WIN32__
#define HOME "z:\\"
/* Make these what you want for cert & key files */
#define CERTF HOME "robert.crt"
#define KEYF HOME "robert.key"
#else
#define HOME "./"
/* Make these what you want for cert & key files */
#define CERTF HOME "foo-cert.pem"
#define KEYF HOME "foo-cert.pem"
#endif
#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }
void main ()
{
int err;
int listen_sd;
int sd;
struct sockaddr_in sa_serv;
struct sockaddr_in sa_cli;
int client_len;
SSL_CTX* ctx;
SSL* ssl;
X509* client_cert;
char* str;
char buf [4096];
SSL_METHOD *meth;
/* SSL preliminaries. We keep the certificate and key with the context. */
RAND_load_file( _argv[0], 64*1024 );
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
meth = SSLv23_server_method();
ctx = SSL_CTX_new (meth);
if (!ctx) {
ERR_print_errors_fp(stderr);
exit(2);
}
if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(3);
}
if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(4);
}
if (!SSL_CTX_check_private_key(ctx)) {
fprintf(stderr,"Private key does not match the certificate public key\n");
exit(5);
}
// SSL_CTX_set_verify_depth( ctx, 1 );
SSL_CTX_set_default_verify_paths(ctx);
SSL_CTX_set_verify( ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, NULL );
/* ----------------------------------------------- */
/* Prepare TCP socket for receiving connections */
#ifdef __WIN32__
WORD VersionRequested;
WSADATA wsaData;
VersionRequested=MAKEWORD(1,1);
err=WSAStartup( VersionRequested, &wsaData );
if (err!=0) return;
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup();
printf( "WSAStartup: Wrong version.\n" );
return;
}
#endif
listen_sd = socket (AF_INET, SOCK_STREAM, 0);
CHK_ERR(listen_sd, "socket");
memset (&sa_serv, '\0', sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons (443); /* Server Port number */
err = bind(listen_sd, (struct sockaddr*) &sa_serv,
sizeof (sa_serv)); CHK_ERR(err, "bind");
/* Receive a TCP connection. */
err = listen (listen_sd, 5); CHK_ERR(err, "listen");
client_len = sizeof(sa_cli);
sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len);
CHK_ERR(sd, "accept");
#ifndef __WIN32__
close (listen_sd);
#else
closesocket( listen_sd );
#endif
printf ("Connection from %lx, port %x\n",
sa_cli.sin_addr.s_addr, sa_cli.sin_port);
/* ----------------------------------------------- */
/* TCP connection is ready. Do server side SSL. */
ssl = SSL_new (ctx);
CHK_NULL(ssl);
SSL_set_fd (ssl, sd);
err = SSL_accept (ssl);
CHK_SSL(err);
/* Get the cipher - opt */
printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
/* Get client's certificate (note: beware of dynamic allocation) - opt */
client_cert = SSL_get_peer_certificate (ssl);
if (client_cert != NULL) {
printf ("Client certificate:\n");
str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
CHK_NULL(str);
printf ("\t subject: %s\n", str);
Free (str);
str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
CHK_NULL(str);
printf ("\t issuer: %s\n", str);
Free (str);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
X509_free (client_cert);
} else
printf ("Client does not have certificate.\n");
/* DATA EXCHANGE - Receive message and send reply. */
err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err);
buf[err] = '\0';
printf ("Got %d chars:'%s'\n", err, buf);
err = SSL_write (ssl, "I hear you.", strlen("I hear you.")); CHK_SSL(err);
/* Clean up. */
#ifndef __WIN32__
close (sd);
#else
closesocket( sd );
#endif
SSL_free (ssl);
SSL_CTX_free (ctx);
#ifdef __WIN32__
WSACleanup();
#endif
}
/* EOF - serv.cpp */