From b300fb773471ffd1d5dbf5415e6a65a090669b31 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Tue, 27 Dec 2011 14:23:22 +0000 Subject: [PATCH] PR: 1794 Submitted by: Peter Sylvester Reviewed by: steve - remove some unncessary SSL_err and permit an srp user callback to allow a worker to obtain a user verifier. - cleanup and comments in s_server and demonstration for asynchronous srp user lookup --- apps/s_server.c | 88 ++++++++++++++++++++++++++++++++++++++++--------- ssl/s3_srvr.c | 23 +++++++++---- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/apps/s_server.c b/apps/s_server.c index e89b888888..2c02fc7d0c 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -380,31 +380,43 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity, /* This is a context that we pass to callbacks */ typedef struct srpsrvparm_st { - int verbose; char *login; SRP_VBASE *vb; + SRP_user_pwd *user; } srpsrvparm; +/* This callback pretends to require some asynchronous logic in order to obtain + a verifier. When the callback is called for a new connection we return + with a negative value. This will provoke the accept etc to return with + an LOOKUP_X509. The main logic of the reinvokes the suspended call + (which would normally occur after a worker has finished) and we + set the user parameters. +*/ static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) { - srpsrvparm *p = (srpsrvparm *) arg; - SRP_user_pwd *user; - - p->login = BUF_strdup(SSL_get_srp_username(s)); - BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login); + srpsrvparm *p = (srpsrvparm *)arg; + if (p->login == NULL && p->user == NULL ) + { + p->login = SSL_get_srp_username(s); + BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login); + return (-1) ; + } - user = SRP_VBASE_get_by_user(p->vb, p->login); - if (user == NULL) + if (p->user == NULL) { BIO_printf(bio_err, "User %s doesn't exist\n", p->login); return SSL3_AL_FATAL; } - if (SSL_set_srp_server_param(s, user->N, user->g, user->s, user->v, - user->info) < 0) + if (SSL_set_srp_server_param(s, p->user->N, p->user->g, p->user->s, p->user->v, + p->user->info) < 0) { *ad = SSL_AD_INTERNAL_ERROR; return SSL3_AL_FATAL; } + BIO_printf(bio_err, "SRP parameters set: username = \"%s\" info=\"%s\" \n", p->login,p->user->info); + /* need to check whether there are memory leaks */ + p->user = NULL; + p->login = NULL; return SSL_ERROR_NONE; } @@ -908,6 +920,9 @@ int MAIN(int, char **); #ifndef OPENSSL_NO_JPAKE static char *jpake_secret = NULL; #endif +#ifndef OPENSSL_NO_SRP + static srpsrvparm srp_callback_parm; +#endif static char *srtp_profiles = NULL; int MAIN(int argc, char *argv[]) @@ -953,7 +968,6 @@ int MAIN(int argc, char *argv[]) #ifndef OPENSSL_NO_SRP char *srpuserseed = NULL; char *srp_verifier_file = NULL; - srpsrvparm p; #endif #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) meth=SSLv23_server_method(); @@ -1842,8 +1856,10 @@ bad: #ifndef OPENSSL_NO_SRP if (srp_verifier_file != NULL) { - p.vb = SRP_VBASE_new(srpuserseed); - if ((ret = SRP_VBASE_init(p.vb, srp_verifier_file)) != SRP_NO_ERROR) + srp_callback_parm.vb = SRP_VBASE_new(srpuserseed); + srp_callback_parm.user = NULL; + srp_callback_parm.login = NULL; + if ((ret = SRP_VBASE_init(srp_callback_parm.vb, srp_verifier_file)) != SRP_NO_ERROR) { BIO_printf(bio_err, "Cannot initialize SRP verifier file \"%s\":ret=%d\n", @@ -1851,7 +1867,7 @@ bad: goto end; } SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE,verify_callback); - SSL_CTX_set_srp_cb_arg(ctx, &p); + SSL_CTX_set_srp_cb_arg(ctx, &srp_callback_parm); SSL_CTX_set_srp_username_callback(ctx, ssl_srp_server_param_cb); } else @@ -2219,6 +2235,16 @@ static int sv_body(char *hostname, int s, unsigned char *context) { static count=0; if (++count == 100) { count=0; SSL_renegotiate(con); } } #endif k=SSL_write(con,&(buf[l]),(unsigned int)i); + while (SSL_get_error(con,k) == SSL_ERROR_WANT_X509_LOOKUP) + { + BIO_printf(bio_s_out,"LOOKUP renego during write\n"); + srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login); + if (srp_callback_parm.user) + BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info); + else + BIO_printf(bio_s_out,"LOOKUP not successful\n"); + k=SSL_write(con,&(buf[l]),(unsigned int)i); + } switch (SSL_get_error(con,k)) { case SSL_ERROR_NONE: @@ -2266,6 +2292,16 @@ static int sv_body(char *hostname, int s, unsigned char *context) { again: i=SSL_read(con,(char *)buf,bufsize); + while (SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP) + { + BIO_printf(bio_s_out,"LOOKUP renego during read\n"); + srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login); + if (srp_callback_parm.user) + BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info); + else + BIO_printf(bio_s_out,"LOOKUP not successful\n"); + i=SSL_read(con,(char *)buf,bufsize); + } switch (SSL_get_error(con,i)) { case SSL_ERROR_NONE: @@ -2278,7 +2314,6 @@ again: break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_s_out,"Read BLOCK\n"); break; case SSL_ERROR_SYSCALL: @@ -2343,7 +2378,18 @@ static int init_ssl_connection(SSL *con) unsigned char *exportedkeymat; - if ((i=SSL_accept(con)) <= 0) + i=SSL_accept(con); + while (i <= 0 && SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP) + { + BIO_printf(bio_s_out,"LOOKUP during accept %s\n",srp_callback_parm.login); + srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login); + if (srp_callback_parm.user) + BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info); + else + BIO_printf(bio_s_out,"LOOKUP not successful\n"); + i=SSL_accept(con); + } + if (i <= 0) { if (BIO_sock_should_retry(i)) { @@ -2567,6 +2613,16 @@ static int www_body(char *hostname, int s, unsigned char *context) if (hack) { i=SSL_accept(con); + while (i <= 0 && SSL_get_error(con,i) == SSL_ERROR_WANT_X509_LOOKUP) + { + BIO_printf(bio_s_out,"LOOKUP during accept %s\n",srp_callback_parm.login); + srp_callback_parm.user = SRP_VBASE_get_by_user(srp_callback_parm.vb, srp_callback_parm.login); + if (srp_callback_parm.user) + BIO_printf(bio_s_out,"LOOKUP done %s\n",srp_callback_parm.user->info); + else + BIO_printf(bio_s_out,"LOOKUP not successful\n"); + i=SSL_accept(con); + } switch (SSL_get_error(con,i)) { diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index bae14c17e5..3609aba5f2 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -338,16 +338,27 @@ int ssl3_accept(SSL *s) case SSL3_ST_SR_CLNT_HELLO_C: s->shutdown=0; - - ret=ssl3_get_client_hello(s); - if (ret <= 0) goto end; + if (s->rwstate != SSL_X509_LOOKUP) + { + ret=ssl3_get_client_hello(s); + if (ret <= 0) goto end; + } #ifndef OPENSSL_NO_SRP { int al; - if ((ret = ssl_check_srp_ext_ClientHello(s,&al)) != SSL_ERROR_NONE) + if ((ret = ssl_check_srp_ext_ClientHello(s,&al)) < 0) + { + /* callback indicates firther work to be done */ + s->rwstate=SSL_X509_LOOKUP; + goto end; + } + if (ret != SSL_ERROR_NONE) { - ssl3_send_alert(s,SSL3_AL_FATAL,al); - SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT); + ssl3_send_alert(s,SSL3_AL_FATAL,al); + /* This is not really an error but the only means to + for a client to detect whether srp is supported. */ + if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY) + SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT); ret = SSL_TLSEXT_ERR_ALERT_FATAL; ret= -1; goto end; -- 2.25.1