* [including the GNU Public Licence.]
*/
/* ====================================================================
- * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* ECC cipher suite support in OpenSSL originally developed by
* SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
*/
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
#ifdef REF_CHECK
# include <assert.h>
#include <openssl/objects.h>
#include <openssl/lhash.h>
#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/ocsp.h>
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
const char *SSL_version_str=OPENSSL_VERSION_TEXT;
ssl_undefined_function,
(int (*)(SSL *, unsigned char *, unsigned char *, int))ssl_undefined_function,
(int (*)(SSL*, int))ssl_undefined_function,
- (int (*)(SSL *, EVP_MD_CTX *, EVP_MD_CTX *, const char*, int, unsigned char *))ssl_undefined_function,
+ (int (*)(SSL *, const char*, int, unsigned char *))ssl_undefined_function,
0, /* finish_mac_length */
- (int (*)(SSL *, EVP_MD_CTX *, unsigned char *))ssl_undefined_function,
+ (int (*)(SSL *, int, unsigned char *))ssl_undefined_function,
NULL, /* client_finished_label */
0, /* client_finished_label_len */
NULL, /* server_finished_label */
0, /* server_finished_label_len */
- (int (*)(int))ssl_undefined_function
+ (int (*)(int))ssl_undefined_function,
+ (int (*)(SSL *, unsigned char *, size_t, const char *,
+ size_t, const unsigned char *, size_t,
+ int use_context)) ssl_undefined_function,
};
int SSL_clear(SSL *s)
* needed because SSL_clear is not called when doing renegotiation) */
/* This is set if we are doing dynamic renegotiation so keep
* the old cipher. It is sort of a SSL_clear_lite :-) */
- if (s->new_session) return(1);
+ if (s->renegotiate) return(1);
#else
- if (s->new_session)
+ if (s->renegotiate)
{
SSLerr(SSL_F_SSL_CLEAR,ERR_R_INTERNAL_ERROR);
return 0;
}
ssl_clear_cipher_ctx(s);
+ ssl_clear_hash_ctx(&s->read_hash);
+ ssl_clear_hash_ctx(&s->write_hash);
s->first_packet=0;
ctx->method=meth;
sk=ssl_create_cipher_list(ctx->method,&(ctx->cipher_list),
- &(ctx->cipher_list_by_id),SSL_DEFAULT_CIPHER_LIST);
+ &(ctx->cipher_list_by_id),
+ meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST);
if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0))
{
SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION,SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
s->ctx=ctx;
+#ifndef OPENSSL_NO_TLSEXT
+ s->tlsext_debug_cb = 0;
+ s->tlsext_debug_arg = NULL;
+ s->tlsext_ticket_expected = 0;
+ s->tlsext_status_type = -1;
+ s->tlsext_status_expected = 0;
+ s->tlsext_ocsp_ids = NULL;
+ s->tlsext_ocsp_exts = NULL;
+ s->tlsext_ocsp_resp = NULL;
+ s->tlsext_ocsp_resplen = -1;
+ CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+ s->initial_ctx=ctx;
+#ifndef OPENSSL_NO_EC
+ if (ctx->tlsext_ecpointformatlist)
+ {
+ s->tlsext_ecpointformatlist =
+ BUF_memdup(ctx->tlsext_ecpointformatlist,
+ ctx->tlsext_ecpointformatlist_length);
+ if (!s->tlsext_ecpointformatlist)
+ goto err;
+ s->tlsext_ecpointformatlist_length =
+ ctx->tlsext_ecpointformatlist_length;
+ }
+ if (ctx->tlsext_ellipticcurvelist)
+ {
+ s->tlsext_ellipticcurvelist =
+ BUF_memdup(ctx->tlsext_ellipticcurvelist,
+ ctx->tlsext_ellipticcurvelist_length);
+ if (!s->tlsext_ellipticcurvelist)
+ goto err;
+ s->tlsext_ellipticcurvelist_length =
+ ctx->tlsext_ellipticcurvelist_length;
+ }
+#endif
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ s->next_proto_negotiated = NULL;
+# endif
+#endif
s->verify_result=X509_V_OK;
CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
+#ifndef OPENSSL_NO_PSK
+ s->psk_client_callback=ctx->psk_client_callback;
+ s->psk_server_callback=ctx->psk_server_callback;
+#endif
+
return(s);
err:
if (s != NULL)
}
CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
- p = (SSL_SESSION *)lh_retrieve(ssl->ctx->sessions, &r);
+ p = lh_SSL_SESSION_retrieve(ssl->ctx->sessions, &r);
CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
return (p != NULL);
}
return X509_VERIFY_PARAM_set_trust(s->param, trust);
}
+int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm)
+ {
+ return X509_VERIFY_PARAM_set1(ctx->param, vpm);
+ }
+
+int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm)
+ {
+ return X509_VERIFY_PARAM_set1(ssl->param, vpm);
+ }
+
void SSL_free(SSL *s)
{
int i;
}
ssl_clear_cipher_ctx(s);
+ ssl_clear_hash_ctx(&s->read_hash);
+ ssl_clear_hash_ctx(&s->write_hash);
if (s->cert != NULL) ssl_cert_free(s->cert);
/* Free up if allocated */
- if (s->ctx) SSL_CTX_free(s->ctx);
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_hostname)
+ OPENSSL_free(s->tlsext_hostname);
+ if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
+#ifndef OPENSSL_NO_EC
+ if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist);
+ if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist);
+#endif /* OPENSSL_NO_EC */
+ if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input);
+ if (s->tlsext_ocsp_exts)
+ sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+ X509_EXTENSION_free);
+ if (s->tlsext_ocsp_ids)
+ sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
+ if (s->tlsext_ocsp_resp)
+ OPENSSL_free(s->tlsext_ocsp_resp);
+#endif
if (s->client_CA != NULL)
sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
if (s->method != NULL) s->method->ssl_free(s);
+ if (s->ctx) SSL_CTX_free(s->ctx);
+
#ifndef OPENSSL_NO_KRB5
if (s->kssl_ctx != NULL)
kssl_ctx_free(s->kssl_ctx);
#endif /* OPENSSL_NO_KRB5 */
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ if (s->next_proto_negotiated)
+ OPENSSL_free(s->next_proto_negotiated);
+#endif
+
+ if (s->srtp_profiles)
+ sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
+
OPENSSL_free(s);
}
}
if (ssl->cert == NULL)
{
- SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
+ SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
return 0;
}
if (ssl->cert->key->x509 == NULL)
int SSL_renegotiate(SSL *s)
{
- if (s->new_session == 0)
- {
- s->new_session=1;
- }
+ if (s->renegotiate == 0)
+ s->renegotiate=1;
+
+ s->new_session=1;
+
+ return(s->method->ssl_renegotiate(s));
+ }
+
+int SSL_renegotiate_abbreviated(SSL *s)
+ {
+ if (s->renegotiate == 0)
+ s->renegotiate=1;
+
+ s->new_session=0;
+
return(s->method->ssl_renegotiate(s));
}
{
/* becomes true when negotiation is requested;
* false again once a handshake has finished */
- return (s->new_session != 0);
+ return (s->renegotiate != 0);
}
long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
case SSL_CTRL_OPTIONS:
return(s->options|=larg);
+ case SSL_CTRL_CLEAR_OPTIONS:
+ return(s->options&=~larg);
case SSL_CTRL_MODE:
return(s->mode|=larg);
+ case SSL_CTRL_CLEAR_MODE:
+ return(s->mode &=~larg);
case SSL_CTRL_GET_MAX_CERT_LIST:
return(s->max_cert_list);
case SSL_CTRL_SET_MAX_CERT_LIST:
s->max_cert_list=larg;
return(l);
case SSL_CTRL_SET_MTU:
- if (SSL_version(s) == DTLS1_VERSION)
+#ifndef OPENSSL_NO_DTLS1
+ if (larg < (long)dtls1_min_mtu())
+ return 0;
+#endif
+
+ if (SSL_version(s) == DTLS1_VERSION ||
+ SSL_version(s) == DTLS1_BAD_VER)
{
s->d1->mtu = larg;
return larg;
return 0;
s->max_send_fragment = larg;
return 1;
+ case SSL_CTRL_GET_RI_SUPPORT:
+ if (s->s3)
+ return s->s3->send_connection_binding;
+ else return 0;
default:
return(s->method->ssl_ctrl(s,cmd,larg,parg));
}
}
}
-struct lhash_st *SSL_CTX_sessions(SSL_CTX *ctx)
+LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx)
{
return ctx->sessions;
}
return(ctx->session_cache_mode);
case SSL_CTRL_SESS_NUMBER:
- return(ctx->sessions->num_items);
+ return(lh_SSL_SESSION_num_items(ctx->sessions));
case SSL_CTRL_SESS_CONNECT:
return(ctx->stats.sess_connect);
case SSL_CTRL_SESS_CONNECT_GOOD:
return(ctx->stats.sess_cache_full);
case SSL_CTRL_OPTIONS:
return(ctx->options|=larg);
+ case SSL_CTRL_CLEAR_OPTIONS:
+ return(ctx->options&=~larg);
case SSL_CTRL_MODE:
return(ctx->mode|=larg);
+ case SSL_CTRL_CLEAR_MODE:
+ return(ctx->mode&=~larg);
case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
return 0;
/* ssl_create_cipher_list may return an empty stack if it
* was unable to find a cipher matching the given rule string
* (for example if the rule string specifies a cipher which
- * has been disabled). This is not an error as far as
- * ssl_create_cipher_list is concerned, and hence
+ * has been disabled). This is not an error as far as
+ * ssl_create_cipher_list is concerned, and hence
* ctx->cipher_list and ctx->cipher_list_by_id has been
* updated. */
if (sk == NULL)
char *SSL_get_shared_ciphers(const SSL *s,char *buf,int len)
{
char *p;
- const char *cp;
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
int i;
sk=s->session->ciphers;
for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
{
- /* Decrement for either the ':' or a '\0' */
- len--;
+ int n;
+
c=sk_SSL_CIPHER_value(sk,i);
- for (cp=c->name; *cp; )
+ n=strlen(c->name);
+ if (n+1 > len)
{
- if (len-- == 0)
- {
- *p='\0';
- return(buf);
- }
- else
- *(p++)= *(cp++);
+ if (p != buf)
+ --p;
+ *p='\0';
+ return buf;
}
+ strcpy(p,c->name);
+ p+=n;
*(p++)=':';
+ len-=n+1;
}
p[-1]='\0';
return(buf);
}
int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
- int (*put_cb)(const SSL_CIPHER *, unsigned char *))
+ int (*put_cb)(const SSL_CIPHER *, unsigned char *))
{
int i,j=0;
SSL_CIPHER *c;
unsigned char *q;
#ifndef OPENSSL_NO_KRB5
- int nokrb5 = !kssl_tgt_is_available(s->kssl_ctx);
+ int nokrb5 = !kssl_tgt_is_available(s->kssl_ctx);
#endif /* OPENSSL_NO_KRB5 */
if (sk == NULL) return(0);
for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
{
c=sk_SSL_CIPHER_value(sk,i);
+ /* Skip TLS v1.2 only ciphersuites if lower than v1.2 */
+ if ((c->algorithm_ssl & SSL_TLSV1_2) &&
+ (TLS1_get_client_version(s) < TLS1_2_VERSION))
+ continue;
#ifndef OPENSSL_NO_KRB5
- if ((c->algorithms & SSL_KRB5) && nokrb5)
- continue;
-#endif /* OPENSSL_NO_KRB5 */
-
+ if (((c->algorithm_mkey & SSL_kKRB5) || (c->algorithm_auth & SSL_aKRB5)) &&
+ nokrb5)
+ continue;
+#endif /* OPENSSL_NO_KRB5 */
+#ifndef OPENSSL_NO_PSK
+ /* with PSK there must be client callback set */
+ if (((c->algorithm_mkey & SSL_kPSK) || (c->algorithm_auth & SSL_aPSK)) &&
+ s->psk_client_callback == NULL)
+ continue;
+#endif /* OPENSSL_NO_PSK */
j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p);
p+=j;
}
+ /* If p == q, no ciphers and caller indicates an error. Otherwise
+ * add SCSV if not renegotiating.
+ */
+ if (p != q && !s->renegotiate)
+ {
+ static SSL_CIPHER scsv =
+ {
+ 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ j = put_cb ? put_cb(&scsv,p) : ssl_put_cipher_by_char(s,&scsv,p);
+ p+=j;
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "SCSV sent by client\n");
+#endif
+ }
+
return(p-q);
}
STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
STACK_OF(SSL_CIPHER) **skp)
{
- SSL_CIPHER *c;
+ const SSL_CIPHER *c;
STACK_OF(SSL_CIPHER) *sk;
int i,n;
+ if (s->s3)
+ s->s3->send_connection_binding = 0;
n=ssl_put_cipher_by_char(s,NULL,NULL);
if ((num%n) != 0)
for (i=0; i<num; i+=n)
{
+ /* Check for SCSV */
+ if (s->s3 && (n != 3 || !p[0]) &&
+ (p[n-2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
+ (p[n-1] == (SSL3_CK_SCSV & 0xff)))
+ {
+ /* SCSV fatal if renegotiating */
+ if (s->renegotiate)
+ {
+ SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
+ }
+ s->s3->send_connection_binding = 1;
+ p += n;
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "SCSV received by server\n");
+#endif
+ continue;
+ }
+
c=ssl_get_cipher_by_char(s,p);
p+=n;
if (c != NULL)
return(NULL);
}
-#ifndef OPENSSL_TLSEXT
-/** return a servername extension value if provided in CLIENT HELLO
- * or NULL.
- * For the moment, only hostname types are supported.
- */
-const char *SSL_get_servername(const SSL *s, const int type) {
+#ifndef OPENSSL_NO_TLSEXT
+/** return a servername extension value if provided in Client Hello, or NULL.
+ * So far, only host_name types are defined (RFC 3546).
+ */
- if (type != TLSEXT_TYPE_SERVER_host)
+const char *SSL_get_servername(const SSL *s, const int type)
+ {
+ if (type != TLSEXT_NAMETYPE_host_name)
return NULL;
- return s->session /*&&s->session->tlsext_hostname*/?s->session->tlsext_hostname:s->tlsext_hostname;
-}
-int SSL_get_servername_type(const SSL *s) {
+ return s->session && !s->tlsext_hostname ?
+ s->session->tlsext_hostname :
+ s->tlsext_hostname;
+ }
- if (s->session &&s->session->tlsext_hostname ?s->session->tlsext_hostname:s->tlsext_hostname)
- return TLSEXT_TYPE_SERVER_host;
+int SSL_get_servername_type(const SSL *s)
+ {
+ if (s->session && (!s->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname))
+ return TLSEXT_NAMETYPE_host_name;
return -1;
+ }
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+/* SSL_select_next_proto implements the standard protocol selection. It is
+ * expected that this function is called from the callback set by
+ * SSL_CTX_set_next_proto_select_cb.
+ *
+ * The protocol data is assumed to be a vector of 8-bit, length prefixed byte
+ * strings. The length byte itself is not included in the length. A byte
+ * string of length 0 is invalid. No byte string may be truncated.
+ *
+ * The current, but experimental algorithm for selecting the protocol is:
+ *
+ * 1) If the server doesn't support NPN then this is indicated to the
+ * callback. In this case, the client application has to abort the connection
+ * or have a default application level protocol.
+ *
+ * 2) If the server supports NPN, but advertises an empty list then the
+ * client selects the first protcol in its list, but indicates via the
+ * API that this fallback case was enacted.
+ *
+ * 3) Otherwise, the client finds the first protocol in the server's list
+ * that it supports and selects this protocol. This is because it's
+ * assumed that the server has better information about which protocol
+ * a client should use.
+ *
+ * 4) If the client doesn't support any of the server's advertised
+ * protocols, then this is treated the same as case 2.
+ *
+ * It returns either
+ * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or
+ * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached.
+ */
+int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, const unsigned char *client, unsigned int client_len)
+ {
+ unsigned int i, j;
+ const unsigned char *result;
+ int status = OPENSSL_NPN_UNSUPPORTED;
+
+ /* For each protocol in server preference order, see if we support it. */
+ for (i = 0; i < server_len; )
+ {
+ for (j = 0; j < client_len; )
+ {
+ if (server[i] == client[j] &&
+ memcmp(&server[i+1], &client[j+1], server[i]) == 0)
+ {
+ /* We found a match */
+ result = &server[i];
+ status = OPENSSL_NPN_NEGOTIATED;
+ goto found;
+ }
+ j += client[j];
+ j++;
+ }
+ i += server[i];
+ i++;
+ }
+
+ /* There's no overlap between our protocols and the server's list. */
+ result = client;
+ status = OPENSSL_NPN_NO_OVERLAP;
+
+ found:
+ *out = (unsigned char *) result + 1;
+ *outlen = result[0];
+ return status;
+ }
+
+/* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's
+ * requested protocol for this connection and returns 0. If the client didn't
+ * request any protocol, then *data is set to NULL.
+ *
+ * Note that the client can request any protocol it chooses. The value returned
+ * from this function need not be a member of the list of supported protocols
+ * provided by the callback.
+ */
+void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, unsigned *len)
+ {
+ *data = s->next_proto_negotiated;
+ if (!*data) {
+ *len = 0;
+ } else {
+ *len = s->next_proto_negotiated_len;
+ }
}
+/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a
+ * TLS server needs a list of supported protocols for Next Protocol
+ * Negotiation. The returned list must be in wire format. The list is returned
+ * by setting |out| to point to it and |outlen| to its length. This memory will
+ * not be modified, but one should assume that the SSL* keeps a reference to
+ * it.
+ *
+ * The callback should return SSL_TLSEXT_ERR_OK if it wishes to advertise. Otherwise, no
+ * such extension will be included in the ServerHello. */
+void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *ctx, int (*cb) (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg), void *arg)
+ {
+ ctx->next_protos_advertised_cb = cb;
+ ctx->next_protos_advertised_cb_arg = arg;
+ }
+
+/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a
+ * client needs to select a protocol from the server's provided list. |out|
+ * must be set to point to the selected protocol (which may be within |in|).
+ * The length of the protocol name must be written into |outlen|. The server's
+ * advertised protocols are provided in |in| and |inlen|. The callback can
+ * assume that |in| is syntactically valid.
+ *
+ * The client must select a protocol. It is fatal to the connection if this
+ * callback returns a value other than SSL_TLSEXT_ERR_OK.
+ */
+void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg), void *arg)
+ {
+ ctx->next_proto_select_cb = cb;
+ ctx->next_proto_select_cb_arg = arg;
+ }
+# endif
#endif
-unsigned long SSL_SESSION_hash(const SSL_SESSION *a)
+
+int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+ const char *label, size_t llen, const unsigned char *p, size_t plen,
+ int use_context)
+ {
+ if (s->version < TLS1_VERSION)
+ return -1;
+
+ return s->method->ssl3_enc->export_keying_material(s, out, olen, label,
+ llen, p, plen,
+ use_context);
+ }
+
+static unsigned long ssl_session_hash(const SSL_SESSION *a)
{
unsigned long l;
* SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being
* able to construct an SSL_SESSION that will collide with any existing session
* with a matching session ID. */
-int SSL_SESSION_cmp(const SSL_SESSION *a,const SSL_SESSION *b)
+static int ssl_session_cmp(const SSL_SESSION *a,const SSL_SESSION *b)
{
if (a->ssl_version != b->ssl_version)
return(1);
* SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each
* variable. The reason is that the functions aren't static, they're exposed via
* ssl.h. */
-static IMPLEMENT_LHASH_HASH_FN(SSL_SESSION_hash, SSL_SESSION *)
-static IMPLEMENT_LHASH_COMP_FN(SSL_SESSION_cmp, SSL_SESSION *)
+static IMPLEMENT_LHASH_HASH_FN(ssl_session, SSL_SESSION)
+static IMPLEMENT_LHASH_COMP_FN(ssl_session, SSL_SESSION)
SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
{
SSL_CTX *ret=NULL;
-
+
if (meth == NULL)
{
SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_NULL_SSL_METHOD_PASSED);
return(NULL);
}
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode() && (meth->version < TLS1_VERSION))
+ {
+ SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+ return NULL;
+ }
+#endif
+
if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0)
{
SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
ret->app_gen_cookie_cb=0;
ret->app_verify_cookie_cb=0;
- ret->sessions=lh_new(LHASH_HASH_FN(SSL_SESSION_hash),
- LHASH_COMP_FN(SSL_SESSION_cmp));
+ ret->sessions=lh_SSL_SESSION_new();
if (ret->sessions == NULL) goto err;
ret->cert_store=X509_STORE_new();
if (ret->cert_store == NULL) goto err;
ssl_create_cipher_list(ret->method,
&ret->cipher_list,&ret->cipher_list_by_id,
- SSL_DEFAULT_CIPHER_LIST);
+ meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST);
if (ret->cipher_list == NULL
|| sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
{
ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
#ifndef OPENSSL_NO_TLSEXT
- ret->tlsext_servername_callback = NULL;
+ ret->tlsext_servername_callback = 0;
ret->tlsext_servername_arg = NULL;
+ /* Setup RFC4507 ticket keys */
+ if ((RAND_pseudo_bytes(ret->tlsext_tick_key_name, 16) <= 0)
+ || (RAND_bytes(ret->tlsext_tick_hmac_key, 16) <= 0)
+ || (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
+ ret->options |= SSL_OP_NO_TICKET;
+
+ ret->tlsext_status_cb = 0;
+ ret->tlsext_status_arg = NULL;
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ ret->next_protos_advertised_cb = 0;
+ ret->next_proto_select_cb = 0;
+# endif
#endif
+#ifndef OPENSSL_NO_PSK
+ ret->psk_identity_hint=NULL;
+ ret->psk_client_callback=NULL;
+ ret->psk_server_callback=NULL;
+#endif
+#ifndef OPENSSL_NO_SRP
+ SSL_CTX_SRP_CTX_init(ret);
+#endif
+#ifndef OPENSSL_NO_BUF_FREELISTS
+ ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT;
+ ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
+ if (!ret->rbuf_freelist)
+ goto err;
+ ret->rbuf_freelist->chunklen = 0;
+ ret->rbuf_freelist->len = 0;
+ ret->rbuf_freelist->head = NULL;
+ ret->wbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
+ if (!ret->wbuf_freelist)
+ {
+ OPENSSL_free(ret->rbuf_freelist);
+ goto err;
+ }
+ ret->wbuf_freelist->chunklen = 0;
+ ret->wbuf_freelist->len = 0;
+ ret->wbuf_freelist->head = NULL;
+#endif
+#ifndef OPENSSL_NO_ENGINE
+ ret->client_cert_engine = NULL;
+#ifdef OPENSSL_SSL_CLIENT_ENGINE_AUTO
+#define eng_strx(x) #x
+#define eng_str(x) eng_strx(x)
+ /* Use specific client engine automatically... ignore errors */
+ {
+ ENGINE *eng;
+ eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
+ if (!eng)
+ {
+ ERR_clear_error();
+ ENGINE_load_builtin_engines();
+ eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
+ }
+ if (!eng || !SSL_CTX_set_client_cert_engine(ret, eng))
+ ERR_clear_error();
+ }
+#endif
+#endif
+ /* Default is to connect to non-RI servers. When RI is more widely
+ * deployed might change this.
+ */
+ ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
+
return(ret);
err:
SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);
{ OPENSSL_free(comp); }
#endif
+#ifndef OPENSSL_NO_BUF_FREELISTS
+static void
+ssl_buf_freelist_free(SSL3_BUF_FREELIST *list)
+ {
+ SSL3_BUF_FREELIST_ENTRY *ent, *next;
+ for (ent = list->head; ent; ent = next)
+ {
+ next = ent->next;
+ OPENSSL_free(ent);
+ }
+ OPENSSL_free(list);
+ }
+#endif
+
void SSL_CTX_free(SSL_CTX *a)
{
int i;
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
if (a->sessions != NULL)
- lh_free(a->sessions);
+ lh_SSL_SESSION_free(a->sessions);
if (a->cert_store != NULL)
X509_STORE_free(a->cert_store);
#else
a->comp_methods = NULL;
#endif
+
+ if (a->srtp_profiles)
+ sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles);
+
+#ifndef OPENSSL_NO_PSK
+ if (a->psk_identity_hint)
+ OPENSSL_free(a->psk_identity_hint);
+#endif
+#ifndef OPENSSL_NO_SRP
+ SSL_CTX_SRP_CTX_free(a);
+#endif
+#ifndef OPENSSL_NO_ENGINE
+ if (a->client_cert_engine)
+ ENGINE_finish(a->client_cert_engine);
+#endif
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+ if (a->wbuf_freelist)
+ ssl_buf_freelist_free(a->wbuf_freelist);
+ if (a->rbuf_freelist)
+ ssl_buf_freelist_free(a->rbuf_freelist);
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+# ifndef OPENSSL_NO_EC
+ if (a->tlsext_ecpointformatlist)
+ OPENSSL_free(a->tlsext_ecpointformatlist);
+ if (a->tlsext_ellipticcurvelist)
+ OPENSSL_free(a->tlsext_ellipticcurvelist);
+# endif /* OPENSSL_NO_EC */
+#endif
+
OPENSSL_free(a);
}
X509_VERIFY_PARAM_set_depth(ctx->param, depth);
}
-void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher)
+void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
{
CERT_PKEY *cpk;
int rsa_enc,rsa_tmp,rsa_sign,dh_tmp,dh_rsa,dh_dsa,dsa_sign;
int rsa_enc_export,dh_rsa_export,dh_dsa_export;
int rsa_tmp_export,dh_tmp_export,kl;
- unsigned long mask,emask;
+ unsigned long mask_k,mask_a,emask_k,emask_a;
int have_ecc_cert, ecdh_ok, ecdsa_ok, ecc_pkey_size;
#ifndef OPENSSL_NO_ECDH
int have_ecdh_tmp;
#endif
X509 *x = NULL;
EVP_PKEY *ecc_pkey = NULL;
- int signature_nid = 0;
+ int signature_nid = 0, pk_nid = 0, md_nid = 0;
if (c == NULL) return;
#endif
#ifndef OPENSSL_NO_ECDH
- have_ecdh_tmp=(c->ecdh_tmp != NULL || c->ecdh_tmp_cb != NULL);
+ have_ecdh_tmp=(c->ecdh_tmp || c->ecdh_tmp_cb || c->ecdh_tmp_auto);
#endif
cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL);
dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
cpk= &(c->pkeys[SSL_PKEY_ECC]);
have_ecc_cert= (cpk->x509 != NULL && cpk->privatekey != NULL);
- mask=0;
- emask=0;
+ mask_k=0;
+ mask_a=0;
+ emask_k=0;
+ emask_a=0;
+
+
#ifdef CIPHER_DEBUG
- printf("rt=%d rte=%d dht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n",
- rsa_tmp,rsa_tmp_export,dh_tmp,
+ printf("rt=%d rte=%d dht=%d ecdht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n",
+ rsa_tmp,rsa_tmp_export,dh_tmp,have_ecdh_tmp,
rsa_enc,rsa_enc_export,rsa_sign,dsa_sign,dh_rsa,dh_dsa);
#endif
+
+ cpk = &(c->pkeys[SSL_PKEY_GOST01]);
+ if (cpk->x509 != NULL && cpk->privatekey !=NULL) {
+ mask_k |= SSL_kGOST;
+ mask_a |= SSL_aGOST01;
+ }
+ cpk = &(c->pkeys[SSL_PKEY_GOST94]);
+ if (cpk->x509 != NULL && cpk->privatekey !=NULL) {
+ mask_k |= SSL_kGOST;
+ mask_a |= SSL_aGOST94;
+ }
if (rsa_enc || (rsa_tmp && rsa_sign))
- mask|=SSL_kRSA;
+ mask_k|=SSL_kRSA;
if (rsa_enc_export || (rsa_tmp_export && (rsa_sign || rsa_enc)))
- emask|=SSL_kRSA;
+ emask_k|=SSL_kRSA;
#if 0
/* The match needs to be both kEDH and aRSA or aDSA, so don't worry */
- if ( (dh_tmp || dh_rsa || dh_dsa) &&
+ if ( (dh_tmp || dh_rsa || dh_dsa) &&
(rsa_enc || rsa_sign || dsa_sign))
- mask|=SSL_kEDH;
+ mask_k|=SSL_kEDH;
if ((dh_tmp_export || dh_rsa_export || dh_dsa_export) &&
(rsa_enc || rsa_sign || dsa_sign))
- emask|=SSL_kEDH;
+ emask_k|=SSL_kEDH;
#endif
- if (dh_tmp_export)
- emask|=SSL_kEDH;
+ if (dh_tmp_export)
+ emask_k|=SSL_kEDH;
if (dh_tmp)
- mask|=SSL_kEDH;
+ mask_k|=SSL_kEDH;
+
+ if (dh_rsa) mask_k|=SSL_kDHr;
+ if (dh_rsa_export) emask_k|=SSL_kDHr;
- if (dh_rsa) mask|=SSL_kDHr;
- if (dh_rsa_export) emask|=SSL_kDHr;
+ if (dh_dsa) mask_k|=SSL_kDHd;
+ if (dh_dsa_export) emask_k|=SSL_kDHd;
- if (dh_dsa) mask|=SSL_kDHd;
- if (dh_dsa_export) emask|=SSL_kDHd;
+ if (emask_k & (SSL_kDHr|SSL_kDHd))
+ mask_a |= SSL_aDH;
if (rsa_enc || rsa_sign)
{
- mask|=SSL_aRSA;
- emask|=SSL_aRSA;
+ mask_a|=SSL_aRSA;
+ emask_a|=SSL_aRSA;
}
if (dsa_sign)
{
- mask|=SSL_aDSS;
- emask|=SSL_aDSS;
+ mask_a|=SSL_aDSS;
+ emask_a|=SSL_aDSS;
}
- mask|=SSL_aNULL;
- emask|=SSL_aNULL;
+ mask_a|=SSL_aNULL;
+ emask_a|=SSL_aNULL;
#ifndef OPENSSL_NO_KRB5
- mask|=SSL_kKRB5|SSL_aKRB5;
- emask|=SSL_kKRB5|SSL_aKRB5;
+ mask_k|=SSL_kKRB5;
+ mask_a|=SSL_aKRB5;
+ emask_k|=SSL_kKRB5;
+ emask_a|=SSL_aKRB5;
#endif
/* An ECC certificate may be usable for ECDH and/or
*/
if (have_ecc_cert)
{
- /* This call populates extension flags (ex_flags) */
+ /* This call populates extension flags (ex_flags) */
x = (c->pkeys[SSL_PKEY_ECC]).x509;
X509_check_purpose(x, -1, 0);
ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
(x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1;
ecc_pkey = X509_get_pubkey(x);
- ecc_pkey_size = (ecc_pkey != NULL) ?
+ ecc_pkey_size = (ecc_pkey != NULL) ?
EVP_PKEY_bits(ecc_pkey) : 0;
EVP_PKEY_free(ecc_pkey);
if ((x->sig_alg) && (x->sig_alg->algorithm))
+ {
signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+ OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
+ }
#ifndef OPENSSL_NO_ECDH
if (ecdh_ok)
{
- if ((signature_nid == NID_md5WithRSAEncryption) ||
- (signature_nid == NID_md4WithRSAEncryption) ||
- (signature_nid == NID_md2WithRSAEncryption))
+
+ if (pk_nid == NID_rsaEncryption || pk_nid == NID_rsa)
{
- mask|=SSL_kECDH|SSL_aRSA;
+ mask_k|=SSL_kECDHr;
+ mask_a|=SSL_aECDH;
if (ecc_pkey_size <= 163)
- emask|=SSL_kECDH|SSL_aRSA;
+ {
+ emask_k|=SSL_kECDHr;
+ emask_a|=SSL_aECDH;
+ }
}
- if (signature_nid == NID_ecdsa_with_SHA1)
+
+ if (pk_nid == NID_X9_62_id_ecPublicKey)
{
- mask|=SSL_kECDH|SSL_aECDSA;
+ mask_k|=SSL_kECDHe;
+ mask_a|=SSL_aECDH;
if (ecc_pkey_size <= 163)
- emask|=SSL_kECDH|SSL_aECDSA;
+ {
+ emask_k|=SSL_kECDHe;
+ emask_a|=SSL_aECDH;
+ }
}
}
#endif
#ifndef OPENSSL_NO_ECDSA
if (ecdsa_ok)
{
- mask|=SSL_aECDSA;
- emask|=SSL_aECDSA;
+ mask_a|=SSL_aECDSA;
+ emask_a|=SSL_aECDSA;
}
#endif
}
#ifndef OPENSSL_NO_ECDH
if (have_ecdh_tmp)
{
- mask|=SSL_kECDHE;
- emask|=SSL_kECDHE;
+ mask_k|=SSL_kEECDH;
+ emask_k|=SSL_kEECDH;
}
#endif
- c->mask=mask;
- c->export_mask=emask;
+
+#ifndef OPENSSL_NO_PSK
+ mask_k |= SSL_kPSK;
+ mask_a |= SSL_aPSK;
+ emask_k |= SSL_kPSK;
+ emask_a |= SSL_aPSK;
+#endif
+
+ c->mask_k=mask_k;
+ c->mask_a=mask_a;
+ c->export_mask_k=emask_k;
+ c->export_mask_a=emask_a;
c->valid=1;
}
#define ku_reject(x, usage) \
(((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
-int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs)
+#ifndef OPENSSL_NO_EC
+
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
{
- unsigned long alg = cs->algorithms;
+ unsigned long alg_k, alg_a;
EVP_PKEY *pkey = NULL;
int keysize = 0;
- int signature_nid = 0;
+ int signature_nid = 0, md_nid = 0, pk_nid = 0;
+ const SSL_CIPHER *cs = s->s3->tmp.new_cipher;
+
+ alg_k = cs->algorithm_mkey;
+ alg_a = cs->algorithm_auth;
if (SSL_C_IS_EXPORT(cs))
{
/* This call populates the ex_flags field correctly */
X509_check_purpose(x, -1, 0);
if ((x->sig_alg) && (x->sig_alg->algorithm))
+ {
signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
- if (alg & SSL_kECDH)
+ OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
+ }
+ if (alg_k & SSL_kECDHe || alg_k & SSL_kECDHr)
{
/* key usage, if present, must allow key agreement */
if (ku_reject(x, X509v3_KU_KEY_AGREEMENT))
{
+ SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT);
return 0;
}
- if (alg & SSL_aECDSA)
+ if ((alg_k & SSL_kECDHe) && TLS1_get_version(s) < TLS1_2_VERSION)
{
/* signature alg must be ECDSA */
- if (signature_nid != NID_ecdsa_with_SHA1)
+ if (pk_nid != NID_X9_62_id_ecPublicKey)
{
+ SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE);
return 0;
}
}
- if (alg & SSL_aRSA)
+ if ((alg_k & SSL_kECDHr) && TLS1_get_version(s) < TLS1_2_VERSION)
{
/* signature alg must be RSA */
- if ((signature_nid != NID_md5WithRSAEncryption) &&
- (signature_nid != NID_md4WithRSAEncryption) &&
- (signature_nid != NID_md2WithRSAEncryption))
+
+ if (pk_nid != NID_rsaEncryption && pk_nid != NID_rsa)
{
+ SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE);
return 0;
}
}
- }
- else if (alg & SSL_aECDSA)
+ }
+ if (alg_a & SSL_aECDSA)
{
/* key usage, if present, must allow signing */
if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
{
+ SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
return 0;
}
}
return 1; /* all checks are ok */
}
+#endif
+
/* THIS NEEDS CLEANING UP */
-X509 *ssl_get_server_send_cert(SSL *s)
+static int ssl_get_server_cert_index(const SSL *s)
{
- unsigned long alg,mask,kalg;
- CERT *c;
- int i,is_export;
+ unsigned long alg_k, alg_a;
- c=s->cert;
- ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
- alg=s->s3->tmp.new_cipher->algorithms;
- is_export=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
- mask=is_export?c->export_mask:c->mask;
- kalg=alg&(SSL_MKEY_MASK|SSL_AUTH_MASK);
+ alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- if (kalg & SSL_kECDH)
+ if (alg_k & (SSL_kECDHr|SSL_kECDHe))
{
- /* we don't need to look at SSL_kECDHE
+ /* we don't need to look at SSL_kEECDH
* since no certificate is needed for
* anon ECDH and for authenticated
- * ECDHE, the check for the auth
+ * EECDH, the check for the auth
* algorithm will set i correctly
* NOTE: For ECDH-RSA, we need an ECC
- * not an RSA cert but for ECDHE-RSA
+ * not an RSA cert but for EECDH-RSA
* we need an RSA cert. Placing the
* checks for SSL_kECDH before RSA
* checks ensures the correct cert is chosen.
*/
- i=SSL_PKEY_ECC;
- }
- else if (kalg & SSL_aECDSA)
- {
- i=SSL_PKEY_ECC;
- }
- else if (kalg & SSL_kDHr)
- i=SSL_PKEY_DH_RSA;
- else if (kalg & SSL_kDHd)
- i=SSL_PKEY_DH_DSA;
- else if (kalg & SSL_aDSS)
- i=SSL_PKEY_DSA_SIGN;
- else if (kalg & SSL_aRSA)
- {
- if (c->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL)
- i=SSL_PKEY_RSA_SIGN;
+ return SSL_PKEY_ECC;
+ }
+ else if (alg_a & SSL_aECDSA)
+ return SSL_PKEY_ECC;
+ else if (alg_k & SSL_kDHr)
+ return SSL_PKEY_DH_RSA;
+ else if (alg_k & SSL_kDHd)
+ return SSL_PKEY_DH_DSA;
+ else if (alg_a & SSL_aDSS)
+ return SSL_PKEY_DSA_SIGN;
+ else if (alg_a & SSL_aRSA)
+ {
+ if (s->cert->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL)
+ return SSL_PKEY_RSA_SIGN;
else
- i=SSL_PKEY_RSA_ENC;
+ return SSL_PKEY_RSA_ENC;
}
- else if (kalg & SSL_aKRB5)
- {
+ else if (alg_a & SSL_aKRB5)
/* VRS something else here? */
- return(NULL);
- }
- else /* if (kalg & SSL_aNULL) */
+ return -1;
+ else if (alg_a & SSL_aGOST94)
+ return SSL_PKEY_GOST94;
+ else if (alg_a & SSL_aGOST01)
+ return SSL_PKEY_GOST01;
+ else /* if (alg_a & SSL_aNULL) */
{
- SSLerr(SSL_F_SSL_GET_SERVER_SEND_CERT,ERR_R_INTERNAL_ERROR);
- return(NULL);
+ SSLerr(SSL_F_SSL_GET_SERVER_CERT_INDEX,ERR_R_INTERNAL_ERROR);
+ return -1;
}
- if (c->pkeys[i].x509 == NULL) return(NULL);
+ }
+
+CERT_PKEY *ssl_get_server_send_pkey(const SSL *s)
+ {
+ CERT *c;
+ int i;
- return(c->pkeys[i].x509);
+ c = s->cert;
+ ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
+
+ i = ssl_get_server_cert_index(s);
+
+ /* This may or may not be an error. */
+ if (i < 0)
+ return NULL;
+
+ /* May be NULL. */
+ return &c->pkeys[i];
}
-EVP_PKEY *ssl_get_sign_pkey(SSL *s,SSL_CIPHER *cipher)
+EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
{
- unsigned long alg;
+ unsigned long alg_a;
CERT *c;
+ int idx = -1;
- alg=cipher->algorithms;
+ alg_a = cipher->algorithm_auth;
c=s->cert;
- if ((alg & SSL_aDSS) &&
+ if ((alg_a & SSL_aDSS) &&
(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL))
- return(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey);
- else if (alg & SSL_aRSA)
+ idx = SSL_PKEY_DSA_SIGN;
+ else if (alg_a & SSL_aRSA)
{
if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL)
- return(c->pkeys[SSL_PKEY_RSA_SIGN].privatekey);
+ idx = SSL_PKEY_RSA_SIGN;
else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL)
- return(c->pkeys[SSL_PKEY_RSA_ENC].privatekey);
- else
- return(NULL);
+ idx = SSL_PKEY_RSA_ENC;
}
- else if ((alg & SSL_aECDSA) &&
+ else if ((alg_a & SSL_aECDSA) &&
(c->pkeys[SSL_PKEY_ECC].privatekey != NULL))
- return(c->pkeys[SSL_PKEY_ECC].privatekey);
- else /* if (alg & SSL_aNULL) */
+ idx = SSL_PKEY_ECC;
+ if (idx == -1)
{
SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR);
return(NULL);
}
+ if (pmd)
+ *pmd = c->pkeys[idx].digest;
+ return c->pkeys[idx].privatekey;
+ }
+
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length)
+ {
+ CERT *c;
+ int i;
+
+ c = s->cert;
+ i = ssl_get_server_cert_index(s);
+
+ if (i == -1)
+ return NULL;
+
+ *authz_length = 0;
+ if (c->pkeys[i].authz == NULL)
+ return(NULL);
+ *authz_length = c->pkeys[i].authz_length;
+
+ return c->pkeys[i].authz;
}
+#endif
void ssl_update_cache(SSL *s,int mode)
{
* 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));
}
}
}
s->handshake_func=s->method->ssl_accept;
/* clear the current cipher */
ssl_clear_cipher_ctx(s);
+ ssl_clear_hash_ctx(&s->read_hash);
+ ssl_clear_hash_ctx(&s->write_hash);
}
void SSL_set_connect_state(SSL *s)
s->handshake_func=s->method->ssl_connect;
/* clear the current cipher */
ssl_clear_cipher_ctx(s);
+ ssl_clear_hash_ctx(&s->read_hash);
+ ssl_clear_hash_ctx(&s->write_hash);
}
int ssl_undefined_function(SSL *s)
const char *SSL_get_version(const SSL *s)
{
- if (s->version == TLS1_VERSION)
+ if (s->version == TLS1_2_VERSION)
+ return("TLSv1.2");
+ else if (s->version == TLS1_1_VERSION)
+ return("TLSv1.1");
+ else if (s->version == TLS1_VERSION)
return("TLSv1");
else if (s->version == SSL3_VERSION)
return("SSLv3");
X509_NAME *xn;
SSL *ret;
int i;
-
+
if ((ret=SSL_new(SSL_get_SSL_CTX(s))) == NULL)
return(NULL);
ret->in_handshake = s->in_handshake;
ret->handshake_func = s->handshake_func;
ret->server = s->server;
+ ret->renegotiate = s->renegotiate;
ret->new_session = s->new_session;
ret->quiet_shutdown = s->quiet_shutdown;
ret->shutdown=s->shutdown;
/* Fix this function so that it takes an optional type parameter */
X509 *SSL_get_certificate(const SSL *s)
{
+ if (s->server)
+ {
+ CERT_PKEY *certpkey;
+ certpkey = ssl_get_server_send_pkey(s);
+ if (certpkey && certpkey->x509)
+ return certpkey->x509;
+ }
+
if (s->cert != NULL)
return(s->cert->key->x509);
else
return(NULL);
}
-SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
{
if ((s->session != NULL) && (s->session->cipher != NULL))
return(s->session->cipher);
s->wbio=BIO_pop(s->wbio);
#ifdef REF_CHECK /* not the usual REF_CHECK, but this avoids adding one more preprocessor symbol */
assert(s->wbio != NULL);
-#endif
+#endif
}
BIO_free(s->bbio);
s->bbio=NULL;
SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
{
-
+ if (ssl->ctx == ctx)
+ return ssl->ctx;
+#ifndef OPENSSL_NO_TLSEXT
+ if (ctx == NULL)
+ ctx = ssl->initial_ctx;
+#endif
if (ssl->cert != NULL)
ssl_cert_free(ssl->cert);
ssl->cert = ssl_cert_dup(ctx->cert);
#endif
void SSL_set_info_callback(SSL *ssl,
- void (*cb)(const SSL *ssl,int type,int val))
+ void (*cb)(const SSL *ssl,int type,int val))
{
ssl->info_callback=cb;
}
return(ssl->state);
}
+void SSL_set_state(SSL *ssl, int state)
+ {
+ ssl->state = state;
+ }
+
void SSL_set_verify_result(SSL *ssl,long arg)
{
ssl->verify_result=arg;
#ifndef OPENSSL_NO_DH
void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int is_export,
- int keylength))
+ int keylength))
{
SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
}
void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export,
- int keylength))
+ int keylength))
{
SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
}
#ifndef OPENSSL_NO_ECDH
void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
- int keylength))
+ int keylength))
{
SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
}
void SSL_set_tmp_ecdh_callback(SSL *ssl,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
- int keylength))
+ int keylength))
{
SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
}
#endif
+#ifndef OPENSSL_NO_PSK
+int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
+ {
+ if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN)
+ {
+ SSLerr(SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
+ return 0;
+ }
+ if (ctx->psk_identity_hint != NULL)
+ OPENSSL_free(ctx->psk_identity_hint);
+ if (identity_hint != NULL)
+ {
+ ctx->psk_identity_hint = BUF_strdup(identity_hint);
+ if (ctx->psk_identity_hint == NULL)
+ return 0;
+ }
+ else
+ ctx->psk_identity_hint = NULL;
+ return 1;
+ }
+
+int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint)
+ {
+ if (s == NULL)
+ return 0;
+
+ if (s->session == NULL)
+ return 1; /* session not created yet, ignored */
+
+ if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN)
+ {
+ SSLerr(SSL_F_SSL_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
+ return 0;
+ }
+ if (s->session->psk_identity_hint != NULL)
+ OPENSSL_free(s->session->psk_identity_hint);
+ if (identity_hint != NULL)
+ {
+ s->session->psk_identity_hint = BUF_strdup(identity_hint);
+ if (s->session->psk_identity_hint == NULL)
+ return 0;
+ }
+ else
+ s->session->psk_identity_hint = NULL;
+ return 1;
+ }
+
+const char *SSL_get_psk_identity_hint(const SSL *s)
+ {
+ if (s == NULL || s->session == NULL)
+ return NULL;
+ return(s->session->psk_identity_hint);
+ }
+
+const char *SSL_get_psk_identity(const SSL *s)
+ {
+ if (s == NULL || s->session == NULL)
+ return NULL;
+ return(s->session->psk_identity);
+ }
+
+void SSL_set_psk_client_callback(SSL *s,
+ unsigned int (*cb)(SSL *ssl, const char *hint,
+ char *identity, unsigned int max_identity_len, unsigned char *psk,
+ unsigned int max_psk_len))
+ {
+ s->psk_client_callback = cb;
+ }
+
+void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx,
+ unsigned int (*cb)(SSL *ssl, const char *hint,
+ char *identity, unsigned int max_identity_len, unsigned char *psk,
+ unsigned int max_psk_len))
+ {
+ ctx->psk_client_callback = cb;
+ }
+
+void SSL_set_psk_server_callback(SSL *s,
+ unsigned int (*cb)(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len))
+ {
+ s->psk_server_callback = cb;
+ }
+
+void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx,
+ unsigned int (*cb)(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len))
+ {
+ ctx->psk_server_callback = cb;
+ }
+#endif
void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
{
SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
}
+/* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
+ * vairable, freeing EVP_MD_CTX previously stored in that variable, if
+ * any. If EVP_MD pointer is passed, initializes ctx with this md
+ * Returns newly allocated ctx;
+ */
+EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md)
+{
+ ssl_clear_hash_ctx(hash);
+ *hash = EVP_MD_CTX_create();
+ if (md) EVP_DigestInit_ex(*hash,md,NULL);
+ return *hash;
+}
+void ssl_clear_hash_ctx(EVP_MD_CTX **hash)
+{
+
+ if (*hash) EVP_MD_CTX_destroy(*hash);
+ *hash=NULL;
+}
+
+void SSL_set_debug(SSL *s, int debug)
+ {
+ s->debug = debug;
+ }
+
+int SSL_cache_hit(SSL *s)
+ {
+ return s->hit;
+ }
#if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
#include "../crypto/bio/bss_file.c"
IMPLEMENT_STACK_OF(SSL_CIPHER)
IMPLEMENT_STACK_OF(SSL_COMP)
+IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER,
+ ssl_cipher_id);