*/
#include <stdio.h>
-#include <openssl/crypto.h>
#include "ssl_locl.h"
#include "kssl_lcl.h"
#include <openssl/buffer.h>
s->in_handshake++;
if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
for (;;)
{
state=s->state;
case SSL3_ST_CR_SRVR_HELLO_A:
case SSL3_ST_CR_SRVR_HELLO_B:
ret=ssl3_get_server_hello(s);
-#ifndef OPENSSL_NO_SRP
- if ((ret == 0) && (s->s3->warn_alert == SSL_AD_MISSING_SRP_USERNAME))
- {
- if (!SRP_have_to_put_srp_username(s))
- {
- SSLerr(SSL_F_SSL3_CONNECT,SSL_R_MISSING_SRP_USERNAME);
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_USER_CANCELLED);
- goto end;
- }
- s->state=SSL3_ST_CW_CLNT_HELLO_A;
- if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; }
- break;
- }
-#endif
if (ret <= 0) goto end;
if (s->hit)
+ {
s->state=SSL3_ST_CR_FINISHED_A;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_ticket_expected)
+ {
+ /* receive renewed session ticket */
+ s->state=SSL3_ST_CR_SESSION_TICKET_A;
+ }
+#endif
+ }
else
- s->state=SSL3_ST_CR_CERT_A;
+ {
+#ifndef OPENSSL_NO_TLSEXT
+ /* The server hello indicated that
+ * an audit proof would follow. */
+ if (s->s3->tlsext_authz_server_promised)
+ s->state=SSL3_ST_CR_SUPPLEMENTAL_DATA_A;
+ else
+#endif
+ s->state=SSL3_ST_CR_CERT_A;
+ }
s->init_num=0;
break;
-
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_CR_SUPPLEMENTAL_DATA_A:
+ case SSL3_ST_CR_SUPPLEMENTAL_DATA_B:
+ ret = tls1_get_server_supplemental_data(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_CERT_A;
+ s->init_num = 0;
+ break;
+#endif
case SSL3_ST_CR_CERT_A:
case SSL3_ST_CR_CERT_B:
#ifndef OPENSSL_NO_TLSEXT
#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
s->state=SSL3_ST_CW_FINISHED_A;
#else
- if (s->next_proto_negotiated)
+ if (s->s3->next_proto_neg_seen)
s->state=SSL3_ST_CW_NEXT_PROTO_A;
else
s->state=SSL3_ST_CW_FINISHED_A;
/* Do the message type and length last */
d=p= &(buf[4]);
+ /* version indicates the negotiated version: for example from
+ * an SSLv2/v3 compatible client hello). The client_version
+ * field is the maximum version we permit and it is also
+ * used in RSA encrypted premaster secrets. Some servers can
+ * choke if we initially report a higher version then
+ * renegotiate to a lower one in the premaster secret. This
+ * didn't happen with TLS 1.0 as most servers supported it
+ * but it can with TLS 1.1 or later if the server only supports
+ * 1.0.
+ *
+ * Possible scenario with previous logic:
+ * 1. Client hello indicates TLS 1.2
+ * 2. Server hello says TLS 1.0
+ * 3. RSA encrypted premaster secret uses 1.2.
+ * 4. Handhaked proceeds using TLS 1.0.
+ * 5. Server sends hello request to renegotiate.
+ * 6. Client hello indicates TLS v1.0 as we now
+ * know that is maximum server supports.
+ * 7. Server chokes on RSA encrypted premaster secret
+ * containing version 1.0.
+ *
+ * For interoperability it should be OK to always use the
+ * maximum version we support in client hello and then rely
+ * on the checking of version to ensure the servers isn't
+ * being inconsistent: for example initially negotiating with
+ * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
+ * client_version in client hello and not resetting it to
+ * the negotiated version.
+ */
+#if 0
*(p++)=s->version>>8;
*(p++)=s->version&0xff;
s->client_version=s->version;
+#else
+ *(p++)=s->client_version>>8;
+ *(p++)=s->client_version&0xff;
+#endif
/* Random stuff */
memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
goto err;
}
+#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
+ /* Some servers hang if client hello > 256 bytes
+ * as hack workaround chop number of supported ciphers
+ * to keep it well below this if we use TLS v1.2
+ */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION
+ && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
+ i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+#endif
s2n(i,p);
p+=i;
{
STACK_OF(SSL_CIPHER) *sk;
const SSL_CIPHER *c;
+ CERT *ct = s->cert;
unsigned char *p,*d;
- int i,al,ok;
+ int i,al=SSL_AD_INTERNAL_ERROR,ok;
unsigned int j;
long n;
#ifndef OPENSSL_NO_COMP
{
if (!ssl_get_new_session(s,0))
{
- al=SSL_AD_INTERNAL_ERROR;
goto f_err;
}
}
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
goto f_err;
}
+ /* If it is a disabled cipher we didn't send it in client hello,
+ * so return an error.
+ */
+ if (c->algorithm_ssl & ct->mask_ssl ||
+ c->algorithm_mkey & ct->mask_k ||
+ c->algorithm_auth & ct->mask_a)
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
+ goto f_err;
+ }
p+=ssl_put_cipher_by_char(s,NULL,NULL);
sk=ssl_get_ciphers_by_id(s);
*/
if (s->session->compress_meth != 0)
{
- al=SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
goto f_err;
}
#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions*/
- if (s->version >= SSL3_VERSION)
+ if (!ssl_parse_serverhello_tlsext(s,&p,d,n))
{
- if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
- {
- /* 'al' set by ssl_parse_serverhello_tlsext */
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
- goto f_err;
- }
- if (ssl_check_serverhello_tlsext(s) <= 0)
- {
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
- goto err;
- }
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
+ goto err;
}
#endif
/* wrong packet length */
al=SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_PACKET_LENGTH);
- goto err;
+ goto f_err;
}
return(1);
if (need_cert)
{
+ int exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+ if (exp_idx >= 0 && i != exp_idx)
+ {
+ x=NULL;
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+ SSL_R_WRONG_CERTIFICATE_TYPE);
+ goto f_err;
+ }
sc->peer_cert_type=i;
CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
/* Why would the following ever happen?
s->session->verify_result = s->verify_result;
x=NULL;
- ret=1;
+#ifndef OPENSSL_NO_TLSEXT
+ /* Check the audit proof. */
+ if (s->ctx->tlsext_authz_server_audit_proof_cb)
+ {
+ ret = s->ctx->tlsext_authz_server_audit_proof_cb(s,
+ s->ctx->tlsext_authz_server_audit_proof_cb_arg);
+ if (ret <= 0)
+ {
+ al = SSL_AD_BAD_CERTIFICATE;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_INVALID_AUDIT_PROOF);
+ goto f_err;
+ }
+ }
+#endif
+ ret=1;
if (0)
{
f_err:
* and the ECParameters in this case is just three bytes.
*/
param_len=3;
- if ((param_len > n) ||
- (*p != NAMED_CURVE_TYPE) ||
- ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0))
+ /* Check curve is one of our prefrences, if not server has
+ * sent an invalid curve.
+ */
+ if (!tls1_check_curve(s, p, param_len))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_CURVE);
+ goto f_err;
+ }
+
+ if ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0)
{
al=SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
{
if (TLS1_get_version(s) >= TLS1_2_VERSION)
{
- int sigalg = tls12_get_sigid(pkey);
- /* Should never happen */
- if (sigalg == -1)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
+ if (rv == -1)
goto err;
- }
- /* Check key type is consistent with signature */
- if (sigalg != (int)p[1])
+ else if (rv == 0)
{
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE);
- al=SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- md = tls12_get_hash(p[0]);
- if (md == NULL)
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
- al=SSL_AD_DECODE_ERROR;
+ al = SSL_AD_DECODE_ERROR;
goto f_err;
}
#ifdef SSL_DEBUG
}
else
{
+ /* aNULL or kPSK do not need public keys */
if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
- /* aNULL or kPSK do not need public keys */
{
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ /* Might be wrong key type, check it */
+ if (ssl3_check_cert_and_algorithm(s))
+ /* Otherwise this shouldn't happen */
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
goto err;
}
/* still data left over */
/* get the certificate types */
ctype_num= *(p++);
+ if (s->cert->ctypes)
+ {
+ OPENSSL_free(s->cert->ctypes);
+ s->cert->ctypes = NULL;
+ }
if (ctype_num > SSL3_CT_NUMBER)
+ {
+ /* If we exceed static buffer copy all to cert structure */
+ s->cert->ctypes = OPENSSL_malloc(ctype_num);
+ memcpy(s->cert->ctypes, p, ctype_num);
+ s->cert->ctype_num = (size_t)ctype_num;
ctype_num=SSL3_CT_NUMBER;
+ }
for (i=0; i<ctype_num; i++)
s->s3->tmp.ctype[i]= p[i];
- p+=ctype_num;
+ p+=p[-1];
if (TLS1_get_version(s) >= TLS1_2_VERSION)
{
n2s(p, llen);
SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_DATA_LENGTH_TOO_LONG);
goto err;
}
+ /* Clear certificate digests and validity flags */
+ for (i = 0; i < SSL_PKEY_NUM; i++)
+ {
+ s->cert->pkeys[i].digest = NULL;
+ s->cert->pkeys[i].valid_flags = 0;
+ }
if ((llen & 1) || !tls1_process_sigalgs(s, p, llen))
{
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
if (n < 6)
{
/* need at least ticket_lifetime_hint + ticket length */
- al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+ al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
goto f_err;
}
/* ticket_lifetime_hint + ticket_length + ticket */
if (ticklen + 6 != n)
{
- al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+ al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
goto f_err;
}
else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
{
DH *dh_srvr,*dh_clnt;
+ SESS_CERT *scert = s->session->sess_cert;
- if (s->session->sess_cert == NULL)
+ if (scert == NULL)
{
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
goto err;
}
- if (s->session->sess_cert->peer_dh_tmp != NULL)
- dh_srvr=s->session->sess_cert->peer_dh_tmp;
+ if (scert->peer_dh_tmp != NULL)
+ dh_srvr=scert->peer_dh_tmp;
else
{
/* we get them from the cert */
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
- goto err;
+ int idx = scert->peer_cert_type;
+ EVP_PKEY *spkey = NULL;
+ dh_srvr = NULL;
+ if (idx >= 0)
+ spkey = X509_get_pubkey(
+ scert->peer_pkeys[idx].x509);
+ if (spkey)
+ {
+ dh_srvr = EVP_PKEY_get1_DH(spkey);
+ EVP_PKEY_free(spkey);
+ }
+ if (dh_srvr == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
}
-
- /* generate a new random key */
- if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
+ if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
{
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
- goto err;
+ /* Use client certificate key */
+ EVP_PKEY *clkey = s->cert->key->privatekey;
+ dh_clnt = NULL;
+ if (clkey)
+ dh_clnt = EVP_PKEY_get1_DH(clkey);
+ if (dh_clnt == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
}
- if (!DH_generate_key(dh_clnt))
+ else
{
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
- DH_free(dh_clnt);
- goto err;
+ /* generate a new random key */
+ if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+ if (!DH_generate_key(dh_clnt))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ DH_free(dh_clnt);
+ goto err;
+ }
}
/* use the 'p' output buffer for the DH key, but
* make sure to clear it out afterwards */
n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
+ if (scert->peer_dh_tmp == NULL)
+ DH_free(dh_srvr);
if (n <= 0)
{
/* clean up */
memset(p,0,n);
- /* send off the data */
- n=BN_num_bytes(dh_clnt->pub_key);
- s2n(n,p);
- BN_bn2bin(dh_clnt->pub_key,p);
- n+=2;
+ if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
+ n = 0;
+ else
+ {
+ /* send off the data */
+ n=BN_num_bytes(dh_clnt->pub_key);
+ s2n(n,p);
+ BN_bn2bin(dh_clnt->pub_key,p);
+ n+=2;
+ }
DH_free(dh_clnt);
return(-1);
}
+/* Check a certificate can be used for client authentication. Currently
+ * check cert exists, if we have a suitable digest for TLS 1.2 if
+ * static DH client certificates can be used and optionally checks
+ * suitability for Suite B.
+ */
+static int ssl3_check_client_certificate(SSL *s)
+ {
+ unsigned long alg_k;
+ if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
+ return 0;
+ /* If no suitable signature algorithm can't use certificate */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION && !s->cert->key->digest)
+ return 0;
+ /* If strict mode check suitability of chain before using it.
+ * This also adjusts suite B digest if necessary.
+ */
+ if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
+ !tls1_check_chain(s, NULL, NULL, NULL, -2))
+ return 0;
+ alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+ /* See if we can use client certificate for fixed DH */
+ if (alg_k & (SSL_kDHr|SSL_kDHd))
+ {
+ SESS_CERT *scert = s->session->sess_cert;
+ int i = scert->peer_cert_type;
+ EVP_PKEY *clkey = NULL, *spkey = NULL;
+ clkey = s->cert->key->privatekey;
+ /* If client key not DH assume it can be used */
+ if (EVP_PKEY_id(clkey) != EVP_PKEY_DH)
+ return 1;
+ if (i >= 0)
+ spkey = X509_get_pubkey(scert->peer_pkeys[i].x509);
+ if (spkey)
+ {
+ /* Compare server and client parameters */
+ i = EVP_PKEY_cmp_parameters(clkey, spkey);
+ EVP_PKEY_free(spkey);
+ if (i != 1)
+ return 0;
+ }
+ s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+ }
+ return 1;
+ }
+
int ssl3_send_client_certificate(SSL *s)
{
X509 *x509=NULL;
if (s->state == SSL3_ST_CW_CERT_A)
{
- if ((s->cert == NULL) ||
- (s->cert->key->x509 == NULL) ||
- (s->cert->key->privatekey == NULL))
- s->state=SSL3_ST_CW_CERT_B;
- else
+ /* Let cert callback update client certificates if required */
+ if (s->cert->cert_cb
+ && s->cert->cert_cb(s, s->cert->cert_cb_arg) <= 0)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
+ return 0;
+ }
+ if (ssl3_check_client_certificate(s))
s->state=SSL3_ST_CW_CERT_C;
+ else
+ s->state=SSL3_ST_CW_CERT_B;
}
/* We need to get a client cert */
if (x509 != NULL) X509_free(x509);
if (pkey != NULL) EVP_PKEY_free(pkey);
+ if (i && !ssl3_check_client_certificate(s))
+ i = 0;
if (i == 0)
{
if (s->version == SSL3_VERSION)
{
s->state=SSL3_ST_CW_CERT_D;
l=ssl3_output_cert_chain(s,
- (s->s3->tmp.cert_req == 2)?NULL:s->cert->key->x509);
+ (s->s3->tmp.cert_req == 2)?NULL:s->cert->key);
s->init_num=(int)l;
s->init_off=0;
}
alg_a=s->s3->tmp.new_cipher->algorithm_auth;
/* we don't have a certificate */
- if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
+ if ((alg_a & (SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
return(1);
sc=s->session->sess_cert;
return 1;
}
}
+ else if (alg_a & SSL_aECDSA)
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_ECDSA_SIGNING_CERT);
+ goto f_err;
+ }
+ else if (alg_k & (SSL_kECDHr|SSL_kECDHe))
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_ECDH_CERT);
+ goto f_err;
+ }
#endif
pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509);
i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey);
}
#endif
#ifndef OPENSSL_NO_DH
- if ((alg_k & SSL_kEDH) &&
+ if ((alg_k & SSL_kEDH) &&
!(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL)))
{
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_KEY);
goto f_err;
}
- else if ((alg_k & SSL_kDHr) && !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
+ else if ((alg_k & SSL_kDHr) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+ !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
{
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_RSA_CERT);
goto f_err;
}
#ifndef OPENSSL_NO_DSA
- else if ((alg_k & SSL_kDHd) && !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
+ else if ((alg_k & SSL_kDHd) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+ !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
{
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_DSA_CERT);
goto f_err;
i = s->ctx->client_cert_cb(s,px509,ppkey);
return i;
}
+
+#ifndef OPENSSL_NO_TLSEXT
+int tls1_get_server_supplemental_data(SSL *s)
+ {
+ int al;
+ int ok;
+ unsigned long supp_data_len, authz_data_len;
+ long n;
+ unsigned short supp_data_type, authz_data_type, proof_len;
+ const unsigned char *p;
+ unsigned char *new_proof;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_SUPPLEMENTAL_DATA_A,
+ SSL3_ST_CR_SUPPLEMENTAL_DATA_B,
+ SSL3_MT_SUPPLEMENTAL_DATA,
+ /* use default limit */
+ TLSEXT_MAXLEN_supplemental_data,
+ &ok);
+
+ if (!ok) return((int)n);
+
+ p = (unsigned char *)s->init_msg;
+
+ /* The message cannot be empty */
+ if (n < 3)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ /* Length of supplemental data */
+ n2l3(p,supp_data_len);
+ n -= 3;
+ /* We must have at least one supplemental data entry
+ * with type (1 byte) and length (2 bytes). */
+ if (supp_data_len != (unsigned long) n || n < 4)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ /* Supplemental data type: must be authz_data */
+ n2s(p,supp_data_type);
+ n -= 2;
+ if (supp_data_type != TLSEXT_SUPPLEMENTALDATATYPE_authz_data)
+ {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE);
+ goto f_err;
+ }
+ /* Authz data length */
+ n2s(p, authz_data_len);
+ n -= 2;
+ if (authz_data_len != (unsigned long) n || n < 1)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ /* Authz data type: must be audit_proof */
+ authz_data_type = *(p++);
+ n -= 1;
+ if (authz_data_type != TLSEXT_AUTHZDATAFORMAT_audit_proof)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_AUTHZ_DATA_TYPE);
+ goto f_err;
+ }
+ /* We have a proof: read its length */
+ if (n < 2)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ n2s(p, proof_len);
+ n -= 2;
+ if (proof_len != (unsigned long) n)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ /* Store the proof */
+ new_proof = OPENSSL_realloc(s->session->audit_proof,
+ proof_len);
+ if (new_proof == NULL)
+ {
+ SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ s->session->audit_proof_length = proof_len;
+ s->session->audit_proof = new_proof;
+ memcpy(s->session->audit_proof, p, proof_len);
+
+ /* Got the proof, but can't verify it yet. */
+ return 1;
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+ }
+#endif