SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG
- SSL_CTX_set_tlsext_servername_arg()
SSL_CTRL_SET_TLSEXT_HOSTNAME - SSL_set_tlsext_hostname()
- SSL_CTRL_SET_TLSEXT_SERVERNAME_DONE
- - SSL_set_tlsext_servername_done()
openssl s_client has a new '-servername' option.
(subject to change); this allows testing the HostName extension for a
specific single host name ('-cert' and '-key' remain fallbacks for
handshakes without HostName negotiation).
+ The option servername_warn allows to return a warning alert instead of
+ a fatal alert in case of servername mismatch.
[Peter Sylvester, Remy Allais, Christophe Renou]
#ifndef OPENSSL_NO_TLSEXT
if (servername != NULL)
{
- if (!SSL_set_tlsext_hostname(con,servername))
+ if (!SSL_set_tlsext_host_name(con,servername))
{
BIO_printf(bio_err,"Unable to set TLS servername extension.\n");
ERR_print_errors(bio_err);
BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
#ifndef OPENSSL_NO_TLSEXT
BIO_printf(bio_err," -servername host - servername for HostName TLS extension\n");
+ BIO_printf(bio_err," -servername_warn - on mismatch send warning (default fatal alert)\n");
BIO_printf(bio_err," -cert2 arg - certificate file to use for servername\n");
BIO_printf(bio_err," (default is %s)\n",TEST_CERT2);
BIO_printf(bio_err," -key2 arg - Private Key file to use for servername, in cert file if\n");
typedef struct tlsextctx_st {
char * servername;
BIO * biodebug;
+ int servername_warn;
} tlsextctx;
BIO_printf(p->biodebug,"Hostname in TLS extension: \"%s\"\n",servername);
if (!p->servername)
- {
- SSL_set_tlsext_servername_done(s,2);
return 1;
- }
if (servername)
{
if (strcmp(servername,p->servername))
- return 0;
- if (ctx2)
+ return p->servername_warn;
+ if (ctx2) {
+ BIO_printf(p->biodebug,"Swiching server context.\n");
SSL_set_SSL_CTX(s,ctx2);
- SSL_set_tlsext_servername_done(s,1);
+ }
}
return 1;
}
#endif
#ifndef OPENSSL_NO_TLSEXT
- tlsextctx tlsextcbp = {NULL, NULL};
+ tlsextctx tlsextcbp = {NULL, NULL, -1};
#endif
#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
meth=SSLv23_server_method();
if (--argc < 1) goto bad;
tlsextcbp.servername= *(++argv);
}
+ else if (strcmp(*argv,"-servername_warn") == 0)
+ { tlsextcbp.servername_warn = 0; }
else if (strcmp(*argv,"-cert2") == 0)
{
if (--argc < 1) goto bad;
ret= -11;*/
goto err;
}
+
if ((buf[0] == 'r') &&
((buf[1] == '\n') || (buf[1] == '\r')))
{
{ERR_FUNC(EC_F_EC_GROUP_GET_ORDER), "EC_GROUP_get_order"},
{ERR_FUNC(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS), "EC_GROUP_get_pentanomial_basis"},
{ERR_FUNC(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS), "EC_GROUP_get_trinomial_basis"},
-{ERR_FUNC(EC_F_EC_GROUP_GROUP2NID), "EC_GROUP_GROUP2NID"},
{ERR_FUNC(EC_F_EC_GROUP_NEW), "EC_GROUP_new"},
{ERR_FUNC(EC_F_EC_GROUP_NEW_BY_CURVE_NAME), "EC_GROUP_new_by_curve_name"},
{ERR_FUNC(EC_F_EC_GROUP_NEW_FROM_DATA), "EC_GROUP_NEW_FROM_DATA"},
ret = 1;
if (parg == NULL)
break;
- if (strlen((char *)parg) > 255)
+ if (strlen((char *)parg) > TLSEXT_MAXLEN_host_name)
{
SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
return 0;
}
s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
break;
- case SSL_CTRL_SET_TLSEXT_SERVERNAME_DONE:
- s->servername_done = larg;
- break;
#endif /* !OPENSSL_NO_TLSEXT */
default:
break;
if (ret <= 0) goto end;
#ifndef OPENSSL_NO_TLSEXT
{
- int al;
- if (ssl_check_tlsext(s,&al) <= 0)
- {
- ssl3_send_alert(s,SSL3_AL_FATAL,al); /* XXX does this *have* to be fatal? */
+ int al,warn;
+ warn = ssl_check_tlsext(s,&al);
+ if (warn == 0)
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ else if (warn < 0) {
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLS_EXT);
ret = -1;
goto end;
- }
+ }
}
#endif
s->new_session = 2;
2 : don't call servername callback, no ack in server hello
*/
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+#define session_ctx initial_ctx
+#else
+#define session_ctx ctx
#endif
};
PEM_ASN1_write_bio_of(SSL_SESSION,i2d_SSL_SESSION,PEM_STRING_SSL_SESSION,bp,x,NULL,NULL,0,NULL,NULL)
#endif
-#define SSL_AD_REASON_OFFSET 1000 /* offset to get SSL_R_... value from SSL_AD_... /
+#define SSL_AD_REASON_OFFSET 1000 /* offset to get SSL_R_... value from SSL_AD_... */
/* These alert types are for SSLv3 and TLSv1 */
#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY
#define SSL_CTRL_SET_MAX_SEND_FRAGMENT 52
-/* see tls.h for macros based on these */
+/* see tls1.h for macros based on these */
#ifndef OPENSSL_NO_TLSEXT
#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
-#define SSL_CTRL_SET_TLSEXT_SERVERNAME_DONE 56
#endif
#define SSL_session_reused(ssl) \
{
if (type != TLSEXT_NAMETYPE_host_name)
return NULL;
- /* XXX cf. SSL_CTRL_GET_TLSEXT_HOSTNAME case in ssl3_ctrl (s3_lib.c) */
- return s->session /*&&s->session->tlsext_hostname*/ ?
+
+ return s->session && !s->tlsext_hostname ?
s->session->tlsext_hostname :
s->tlsext_hostname;
}
int SSL_get_servername_type(const SSL *s)
{
- if (s->session &&s->session->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname)
+ if (s->session && (!s->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname))
return TLSEXT_NAMETYPE_host_name;
return -1;
}
* and it would be rather hard to do anyway :-) */
if (s->session->session_id_length == 0) return;
- i=s->ctx->session_cache_mode;
+ i=s->session_ctx->session_cache_mode;
if ((i & mode) && (!s->hit)
&& ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
- || SSL_CTX_add_session(s->ctx,s->session))
- && (s->ctx->new_session_cb != NULL))
+ || SSL_CTX_add_session(s->session_ctx,s->session))
+ && (s->session_ctx->new_session_cb != NULL))
{
CRYPTO_add(&s->session->references,1,CRYPTO_LOCK_SSL_SESSION);
- if (!s->ctx->new_session_cb(s,s->session))
+ if (!s->session_ctx->new_session_cb(s,s->session))
SSL_SESSION_free(s->session);
}
((i & mode) == mode))
{
if ( (((mode & SSL_SESS_CACHE_CLIENT)
- ?s->ctx->stats.sess_connect_good
- :s->ctx->stats.sess_accept_good) & 0xff) == 0xff)
+ ?s->session_ctx->stats.sess_connect_good
+ :s->session_ctx->stats.sess_accept_good) & 0xff) == 0xff)
{
- SSL_CTX_flush_sessions(s->ctx,(unsigned long)time(NULL));
+ SSL_CTX_flush_sessions(s->session_ctx,(unsigned long)time(NULL));
}
}
}
SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
{
+ if (ssl->ctx == ctx)
+ return ssl->ctx;
+ if (ctx == NULL)
+ ctx = ssl->initial_ctx;
if (ssl->cert != NULL)
ssl_cert_free(ssl->cert);
ssl->cert = ssl_cert_dup(ctx->cert);
#include <openssl/rand.h>
#include "ssl_locl.h"
-#ifndef OPENSSL_NO_TLSEXT
-#define session_ctx initial_ctx
-#else
-#define session_ctx ctx
-#endif
-
static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s);
static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
if (s->session_ctx->session_timeout == 0)
ss->timeout=SSL_get_default_timeout(s);
else
- ss->timeout=s->ctx->session_timeout;
+ ss->timeout=s->session_ctx->session_timeout;
if (s->session != NULL)
{
SSL_SESSION_free(ss);
return(0);
}
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_hostname) {
+ ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
+ if (ss->tlsext_hostname == NULL) {
+ SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR);
+ SSL_SESSION_free(ss);
+ return 0;
+ }
+ }
+#endif
}
else
{
{
int extdatalen=0;
unsigned char *ret = p;
- if (s->hit || s->servername_done == 2)
- return p;
- ret+=2;
- if (s->servername_done == 1)
- s->servername_done = 2;
+ ret+=2;
if (ret>=limit) return NULL; /* this really never occurs, but ... */
- if (s->session->tlsext_hostname != NULL)
+ if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
{
if (limit - p - 4 < 0) return NULL;
unsigned short size;
unsigned short len;
unsigned char *data = *p;
+#if 0
+ fprintf(stderr,"ssl_parse_clienthello_tlsext %s\n",s->session->tlsext_hostname?s->session->tlsext_hostname:"NULL");
+#endif
+ s->servername_done = 0;
if (data >= (d+n-2))
return 1;
if (data+size > (d+n))
return 1;
+/* The servername extension is treated as follows:
+
+ - Only the hostname type is supported with a maximum length of 255.
+ - The servername is rejected if too long or if it contains zeros,
+ in which case an fatal alert is generated.
+ - The servername field is maintained together with the session cache.
+ - When a session is resumed, the servername call back invoked in order
+ to allow the application to position itself to the right context.
+ - The servername is acknowledged if it is new for a session or when
+ it is identical to a previously used for the same session.
+ Applications can control the behaviour. They can at any time
+ set a 'desirable' servername for a new SSL object. This can be the
+ case for example with HTTPS when a Host: header field is received and
+ a renegotiation is requested. In this case, a possible servername
+ presented in the new client hello is only acknowledged if it matches
+ the value of the Host: field.
+ - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ if they provide for changing an explicit servername context for the session,
+ i.e. when the session has been established with a servername extension.
+ - On session reconnect, the servername extension may be absent.
+
+*/
+
if (type == TLSEXT_TYPE_server_name)
{
unsigned char *sdata = data;
case TLSEXT_NAMETYPE_host_name:
if (s->session->tlsext_hostname == NULL)
{
- if (len > 255 ||
+ if (len > TLSEXT_MAXLEN_host_name ||
((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL))
{
*al = TLS1_AD_UNRECOGNIZED_NAME;
return 0;
}
-
memcpy(s->session->tlsext_hostname, sdata, len);
- s->session->tlsext_hostname[len]='\0';
+ s->session->tlsext_hostname[len]='\0';
+ if (strlen(s->session->tlsext_hostname) != len) {
+ OPENSSL_free(s->session->tlsext_hostname);
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
}
+ s->servername_done = 1;
+
+#if 0
+ fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_hostname %s\n",s->session->tlsext_hostname);
+#endif
+ }
+ else
+ s->servername_done = strlen(s->session->tlsext_hostname) == len
+ && strncmp(s->session->tlsext_hostname,sdata, len) == 0;
+
break;
default:
int ret;
*al = SSL_AD_UNRECOGNIZED_NAME;
- if (s->servername_done == 0 && (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0))
+ if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
{
ret = s->ctx->tlsext_servername_callback(s, al, s->ctx->tlsext_servername_arg);
if (ret <= 0)
return ret;
}
- if (s->servername_done == 1)
- s->servername_done = 2;
+ else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
+ {
+ ret = s->initial_ctx->tlsext_servername_callback(s, al, s->initial_ctx->tlsext_servername_arg);
+ if (ret <= 0)
+ return ret;
+ }
return 1;
}
#ifndef OPENSSL_NO_TLSEXT
+#define TLSEXT_MAXLEN_host_name 255
+
const char *SSL_get_servername(const SSL *s, const int type) ;
int SSL_get_servername_type(const SSL *s) ;
-#define SSL_set_tlsext_hostname(s,name) \
+#define SSL_set_tlsext_host_name(s,name) \
SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \