#include <openssl/rand.h>
#include <openssl/objects.h>
#include <openssl/evp.h>
+#include <openssl/hmac.h>
#include <openssl/x509.h>
+#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
+#endif
#include <openssl/bn.h>
#ifndef OPENSSL_NO_KRB5
#include <openssl/krb5_asn.h>
#include <openssl/md5.h>
static SSL_METHOD *ssl3_get_server_method(int ver);
-
#ifndef OPENSSL_NO_ECDH
static int nid2curve_id(int nid);
#endif
return(NULL);
}
-SSL_METHOD *SSLv3_server_method(void)
- {
- static int init=1;
- static SSL_METHOD SSLv3_server_data;
-
- if (init)
- {
- CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
-
- if (init)
- {
- memcpy((char *)&SSLv3_server_data,(char *)sslv3_base_method(),
- sizeof(SSL_METHOD));
- SSLv3_server_data.ssl_accept=ssl3_accept;
- SSLv3_server_data.get_ssl_method=ssl3_get_server_method;
- init=0;
- }
-
- CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
- }
- return(&SSLv3_server_data);
- }
+IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
+ ssl3_accept,
+ ssl_undefined_function,
+ ssl3_get_server_method)
int ssl3_accept(SSL *s)
{
BUF_MEM *buf;
- unsigned long l,Time=time(NULL);
+ unsigned long l,Time=(unsigned long)time(NULL);
void (*cb)(const SSL *ssl,int type,int val)=NULL;
long num1;
int ret= -1;
case SSL3_ST_SW_CERT_A:
case SSL3_ST_SW_CERT_B:
- /* Check if it is anon DH or anon ECDH */
- if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+ /* Check if it is anon DH or anon ECDH or KRB5 */
+ if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL)
+ && !(s->s3->tmp.new_cipher->algorithms & SSL_aKRB5))
{
ret=ssl3_send_server_certificate(s);
if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_SW_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+ else
+ {
+ skip = 1;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+#else
}
else
skip=1;
+
s->state=SSL3_ST_SW_KEY_EXCH_A;
+#endif
s->init_num=0;
break;
if (ret <= 0) goto end;
if (s->hit)
s->state=SSL_ST_OK;
+#ifndef OPENSSL_NO_TLSEXT
+ else if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_SW_SESSION_TICKET_A;
+#endif
else
s->state=SSL3_ST_SW_CHANGE_A;
s->init_num=0;
break;
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_SW_SESSION_TICKET_A:
+ case SSL3_ST_SW_SESSION_TICKET_B:
+ ret=ssl3_send_newsession_ticket(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_CHANGE_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_STATUS_A:
+ case SSL3_ST_SW_CERT_STATUS_B:
+ ret=ssl3_send_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+
+#endif
+
case SSL3_ST_SW_CHANGE_A:
case SSL3_ST_SW_CHANGE_B:
unsigned long id;
unsigned char *p,*d,*q;
SSL_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
SSL_COMP *comp=NULL;
+#endif
STACK_OF(SSL_CIPHER) *ciphers=NULL;
/* We do this so that we will respond with our native type.
*/
if (s->state == SSL3_ST_SR_CLNT_HELLO_A)
{
- s->first_packet=1;
s->state=SSL3_ST_SR_CLNT_HELLO_B;
}
+ s->first_packet=1;
n=s->method->ssl_get_message(s,
SSL3_ST_SR_CLNT_HELLO_B,
SSL3_ST_SR_CLNT_HELLO_C,
&ok);
if (!ok) return((int)n);
+ s->first_packet=0;
d=p=(unsigned char *)s->init_msg;
/* use version from inside client hello, not from record header
s->client_version=(((int)p[0])<<8)|(int)p[1];
p+=2;
- if (s->client_version < s->version)
+ if ((s->version == DTLS1_VERSION && s->client_version > s->version) ||
+ (s->version != DTLS1_VERSION && s->client_version < s->version))
{
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
if ((s->client_version>>8) == SSL3_VERSION_MAJOR)
* might be written that become totally unsecure when compiled with
* an earlier library version)
*/
- if (j == 0 || (s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
+ if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
{
if (!ssl_get_new_session(s,1))
goto err;
}
else
{
- i=ssl_get_prev_session(s,p,j);
+ i=ssl_get_prev_session(s, p, j, d + n);
if (i == 1)
{ /* previous session */
s->hit=1;
p+=j;
- if (SSL_version(s) == DTLS1_VERSION)
+ if (s->version == DTLS1_VERSION)
{
/* cookie stuff */
cookie_len = *(p++);
goto f_err;
}
+#ifndef OPENSSL_NO_TLSEXT
+ /* TLS extensions*/
+ if (s->version > SSL3_VERSION)
+ {
+ if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
+ {
+ /* 'al' set by ssl_parse_clienthello_tlsext */
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
+ goto f_err;
+ }
+ }
+ if (ssl_check_clienthello_tlsext(s) <= 0) {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
+#endif
/* Worst case, we will use the NULL compression, but if we have other
* options, we will now look for them. We have i-1 compression
* algorithms from the client, starting at q. */
s->s3->tmp.new_compression=NULL;
+#ifndef OPENSSL_NO_COMP
if (s->ctx->comp_methods != NULL)
{ /* See if we have a match */
int m,nn,o,v,done=0;
else
comp=NULL;
}
+#endif
/* TLS does not mind if there is extra stuff */
#if 0 /* SSL 3.0 does not mind either, so we should disable this test
if (!s->hit)
{
+#ifdef OPENSSL_NO_COMP
+ s->session->compress_meth=0;
+#else
s->session->compress_meth=(comp == NULL)?0:comp->id;
+#endif
if (s->session->ciphers != NULL)
sk_SSL_CIPHER_free(s->session->ciphers);
s->session->ciphers=ciphers;
{
buf=(unsigned char *)s->init_buf->data;
p=s->s3->server_random;
- Time=time(NULL); /* Time */
+ Time=(unsigned long)time(NULL); /* Time */
l2n(Time,p);
if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
return -1;
p+=i;
/* put the compression method */
+#ifdef OPENSSL_NO_COMP
+ *(p++)=0;
+#else
if (s->s3->tmp.new_compression == NULL)
*(p++)=0;
else
*(p++)=s->s3->tmp.new_compression->id;
-
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+ if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+#endif
/* do the header */
l=(p-d);
d=buf;
/* XXX: For now, we only support named (not
* generic) curves in ECDH ephemeral key exchanges.
- * In this situation, we need three additional bytes
+ * In this situation, we need four additional bytes
* to encode the entire ServerECDHParams
* structure.
*/
- n = 3 + encodedlen;
+ n = 4 + encodedlen;
/* We'll generate the serverKeyExchange message
* explicitly so we can set these to NULLs
r[0]=NULL;
r[1]=NULL;
r[2]=NULL;
+ r[3]=NULL;
}
else
#endif /* !OPENSSL_NO_ECDH */
{
/* XXX: For now, we only support named (not generic) curves.
* In this situation, the serverKeyExchange message has:
- * [1 byte CurveType], [1 byte CurveName]
+ * [1 byte CurveType], [2 byte CurveName]
* [1 byte length of encoded point], followed by
* the actual encoded point itself
*/
*p = NAMED_CURVE_TYPE;
p += 1;
+ *p = 0;
+ p += 1;
*p = curve_id;
p += 1;
*p = encodedlen;
return(-1);
}
-
-static const int KDF1_SHA1_len = 20;
-static void *KDF1_SHA1(const void *in, size_t inlen, void *out, size_t *outlen)
- {
-#ifndef OPENSSL_NO_SHA
- if (*outlen < SHA_DIGEST_LENGTH)
- return NULL;
- else
- *outlen = SHA_DIGEST_LENGTH;
- return SHA1(in, inlen, out);
-#else
- return NULL;
-#endif
- }
-
int ssl3_get_client_key_exchange(SSL *s)
{
int i,al,ok;
rsa=pkey->pkey.rsa;
}
- /* TLS */
- if (s->version > SSL3_VERSION)
+ /* TLS and [incidentally] DTLS, including pre-0.9.8f */
+ if (s->version > SSL3_VERSION &&
+ s->client_version != DTLS1_BAD_VER)
{
n2s(p,i);
if (n != i+2)
n2s(p,i);
enc_ticket.length = i;
- if (n < enc_ticket.length + 6)
+ if (n < (int)enc_ticket.length + 6)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
SSL_R_DATA_LENGTH_TOO_LONG);
n2s(p,i);
authenticator.length = i;
- if (n < enc_ticket.length + authenticator.length + 6)
+ if (n < (int)(enc_ticket.length + authenticator.length) + 6)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
SSL_R_DATA_LENGTH_TOO_LONG);
SSL_R_DATA_LENGTH_TOO_LONG);
goto err;
}
+ if (!((pms[0] == (s->client_version>>8)) && (pms[1] == (s->client_version & 0xff))))
+ {
+ /* The premaster secret must contain the same version number as the
+ * ClientHello to detect version rollback attacks (strangely, the
+ * protocol does not offer such protection for DH ciphersuites).
+ * However, buggy clients exist that send random bytes instead of
+ * the protocol version.
+ * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients.
+ * (Perhaps we should have a separate BUG value for the Kerberos cipher)
+ */
+ if (!(s->options & SSL_OP_TLS_ROLLBACK_BUG))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+ }
+
EVP_CIPHER_CTX_cleanup(&ciph_ctx);
s->session->master_key_length=
if (kssl_ctx->client_princ)
{
- int len = strlen(kssl_ctx->client_princ);
+ size_t len = strlen(kssl_ctx->client_princ);
if ( len < SSL_MAX_KRB5_PRINCIPAL_LENGTH )
{
s->session->krb5_client_princ_len = len;
if (l & SSL_kECDH)
{
/* use the certificate */
- tkey = s->cert->key->privatekey->pkey.ec;
+ tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
}
else
{
goto f_err;
}
- EC_POINT_copy(clnt_ecpoint,
- EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec));
+ if (EC_POINT_copy(clnt_ecpoint,
+ EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) == 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
ret = 2; /* Skip certificate verify processing */
}
else
ERR_R_ECDH_LIB);
goto err;
}
- /* If field size is not more than 24 octets, then use SHA-1 hash of result;
- * otherwise, use result (see section 4.8 of draft-ietf-tls-ecc-03.txt;
- * this is new with this version of the Internet Draft).
- */
- if (field_size <= 24 * 8)
- i = ECDH_compute_key(p, KDF1_SHA1_len, clnt_ecpoint, srvr_ecdh, KDF1_SHA1);
- else
- i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL);
+ i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL);
if (i <= 0)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
}
}
#endif
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_send_newsession_ticket(SSL *s)
+ {
+ if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
+ {
+ unsigned char *p, *senc, *macstart;
+ int len, slen;
+ unsigned int hlen;
+ EVP_CIPHER_CTX ctx;
+ HMAC_CTX hctx;
+
+ /* get session encoding length */
+ slen = i2d_SSL_SESSION(s->session, NULL);
+ /* Some length values are 16 bits, so forget it if session is
+ * too long
+ */
+ if (slen > 0xFF00)
+ return -1;
+ /* Grow buffer if need be: the length calculation is as
+ * follows 1 (size of message name) + 3 (message length
+ * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) +
+ * 16 (key name) + max_iv_len (iv length) +
+ * session_length + max_enc_block_size (max encrypted session
+ * length) + max_md_size (HMAC).
+ */
+ if (!BUF_MEM_grow(s->init_buf,
+ 26 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH +
+ EVP_MAX_MD_SIZE + slen))
+ return -1;
+ senc = OPENSSL_malloc(slen);
+ if (!senc)
+ return -1;
+ p = senc;
+ i2d_SSL_SESSION(s->session, &p);
+
+ p=(unsigned char *)s->init_buf->data;
+ /* do the header */
+ *(p++)=SSL3_MT_NEWSESSION_TICKET;
+ /* Skip message length for now */
+ p += 3;
+ l2n(s->session->tlsext_tick_lifetime_hint, p);
+ /* Skip ticket length for now */
+ p += 2;
+ /* Output key name */
+ macstart = p;
+ memcpy(p, s->ctx->tlsext_tick_key_name, 16);
+ p += 16;
+ /* Generate and output IV */
+ RAND_pseudo_bytes(p, 16);
+ EVP_CIPHER_CTX_init(&ctx);
+ /* Encrypt session data */
+ EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ s->ctx->tlsext_tick_aes_key, p);
+ p += 16;
+ EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
+ p += len;
+ EVP_EncryptFinal(&ctx, p, &len);
+ p += len;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ HMAC_CTX_init(&hctx);
+ HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
+ tlsext_tick_md(), NULL);
+ HMAC_Update(&hctx, macstart, p - macstart);
+ HMAC_Final(&hctx, p, &hlen);
+ HMAC_CTX_cleanup(&hctx);
+
+ p += hlen;
+ /* Now write out lengths: p points to end of data written */
+ /* Total length */
+ len = p - (unsigned char *)s->init_buf->data;
+ p=(unsigned char *)s->init_buf->data + 1;
+ l2n3(len - 4, p); /* Message length */
+ p += 4;
+ s2n(len - 10, p); /* Ticket length */
+
+ /* number of bytes to write */
+ s->init_num= len;
+ s->state=SSL3_ST_SW_SESSION_TICKET_B;
+ s->init_off=0;
+ OPENSSL_free(senc);
+ }
+
+ /* SSL3_ST_SW_SESSION_TICKET_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int ssl3_send_cert_status(SSL *s)
+ {
+ if (s->state == SSL3_ST_SW_CERT_STATUS_A)
+ {
+ unsigned char *p;
+ /* Grow buffer if need be: the length calculation is as
+ * follows 1 (message type) + 3 (message length) +
+ * 1 (ocsp response type) + 3 (ocsp response length)
+ * + (ocsp response)
+ */
+ if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen))
+ return -1;
+
+ p=(unsigned char *)s->init_buf->data;
+
+ /* do the header */
+ *(p++)=SSL3_MT_CERTIFICATE_STATUS;
+ /* message length */
+ l2n3(s->tlsext_ocsp_resplen + 4, p);
+ /* status type */
+ *(p++)= s->tlsext_status_type;
+ /* length of OCSP response */
+ l2n3(s->tlsext_ocsp_resplen, p);
+ /* actual response */
+ memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
+ /* number of bytes to write */
+ s->init_num = 8 + s->tlsext_ocsp_resplen;
+ s->state=SSL3_ST_SW_CERT_STATUS_B;
+ s->init_off = 0;
+ }
+
+ /* SSL3_ST_SW_CERT_STATUS_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+#endif