Implement the Opaque PRF Input TLS extension

(draft-rescorla-tls-opaque-prf-input-00.txt), and do some cleanups and
bugfixes on the way.  In particular, this fixes the buffer bounds
checks in ssl_add_clienthello_tlsext() and in ssl_add_serverhello_tlsext().

Note that the opaque PRF Input TLS extension is not compiled by default;
see CHANGES.
This commit is contained in:
Bodo Möller 2007-09-21 06:54:24 +00:00
parent 54ef01b54b
commit 761772d7e1
16 changed files with 544 additions and 89 deletions

58
CHANGES
View file

@ -4,6 +4,64 @@
Changes between 0.9.8f and 0.9.9 [xx XXX xxxx]
*) Implement Opaque PRF Input TLS extension as specified in
draft-rescorla-tls-opaque-prf-input-00.txt. Since this is not an
official specification yet and no extension type assignment by
IANA exists, this extension (for now) will have to be explicitly
enabled when building OpenSSL by providing the extension number
to use. For example, specify an option
-DTLSEXT_TYPE_opaque_prf_input=0x9527
to the "config" or "Configure" script to enable the extension,
assuming extension number 0x9527 (which is a completely arbitrary
and unofficial assignment based on the MD5 hash of the Internet
Draft). Note that by doing so, you potentially lose
interoperability with other TLS implementations since these might
be using the same extension number for other purposes.
SSL_set_tlsext_opaque_prf_input(ssl, src, len) is used to set the
opaque PRF input value to use in the handshake. This will create
an interal copy of the length-'len' string at 'src', and will
return non-zero for success.
To get more control and flexibility, provide a callback function
by using
SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb)
SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg)
where
int (*cb)(SSL *, void *peerinput, size_t len, void *arg);
void *arg;
Callback function 'cb' will be called in handshakes, and is
expected to use SSL_set_tlsext_opaque_prf_input() as appropriate.
Argument 'arg' is for application purposes (the value as given to
SSL_CTX_set_tlsext_opaque_prf_input_callback_arg() will directly
be provided to the callback function). The callback function
has to return non-zero to report success: usually 1 to use opaque
PRF input just if possible, or 2 to enforce use of the opaque PRF
input. In the latter case, the library will abort the handshake
if opaque PRF input is not successfully negotiated.
Arguments 'peerinput' and 'len' given to the callback function
will always be NULL and 0 in the case of a client. A server will
see the client's opaque PRF input through these variables if
available (NULL and 0 otherwise). Note that if the server
provides an opaque PRF input, the length must be the same as the
length of the client's opaque PRF input.
Note that the callback function will only be called when creating
a new session (session resumption can resume whatever was
previously negotiated), and will not be called in SSL 2.0
handshakes; thus, SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) or
SSL_set_options(ssl, SSL_OP_NO_SSLv2) is especially recommended
for applications that need to enforce opaque PRF input.
[Bodo Moeller]
*) Update ssl code to support digests other than SHA1+MD5 for handshake
MAC.

View file

@ -638,6 +638,11 @@ void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
extname = "server ticket";
break;
#ifdef TLSEXT_TYPE_opaque_prf_input
case TLSEXT_TYPE_opaque_prf_input:
extname = "opaque PRF input";
break;
#endif
default:
extname = "unknown";

View file

@ -859,6 +859,11 @@ bad:
}
#endif /* OPENSSL_NO_KRB5 */
/* SSL_set_cipher_list(con,"RC4-MD5"); */
#if 0
#ifdef TLSEXT_TYPE_opaque_prf_input
SSL_set_tlsext_opaque_prf_input(con, "Test client", 1);
#endif
#endif
re_start:
@ -1073,11 +1078,13 @@ re_start:
if (in_init)
{
in_init=0;
#if 0 /* This test doesn't really work as intended (needs to be fixed) */
#ifndef OPENSSL_NO_TLSEXT
if (servername != NULL && !SSL_session_reused(con))
{
BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
}
#endif
#endif
if (sess_out)
{

View file

@ -1575,6 +1575,11 @@ static int sv_body(char *hostname, int s, unsigned char *context)
strlen((char *)context));
}
SSL_clear(con);
#if 0
#ifdef TLSEXT_TYPE_opaque_prf_input
SSL_set_tlsext_opaque_prf_input(con, "Test server", 1);
#endif
#endif
if (SSL_version(con) == DTLS1_VERSION)
{

View file

@ -277,6 +277,19 @@ static int ssl23_client_hello(SSL *s)
version = SSL2_VERSION;
}
if (version != SSL2_VERSION)
{
/* have to disable SSL 2.0 compatibility if we need TLS extensions */
if (s->tlsext_hostname != NULL)
ssl2_compat = 0;
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL)
ssl2_compat = 0;
#endif
}
buf=(unsigned char *)s->init_buf->data;
if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
{
@ -420,6 +433,12 @@ static int ssl23_client_hello(SSL *s)
*(p++)=0; /* Add the NULL method */
#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions*/
if (ssl_prepare_clienthello_tlsext(s) <= 0)
{
SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
return -1;
}
if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
{
SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);

View file

@ -656,7 +656,9 @@ int ssl3_client_hello(SSL *s)
}
#endif
*(p++)=0; /* Add the NULL method */
#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions*/
if (ssl_prepare_clienthello_tlsext(s) <= 0)
{
SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
@ -853,6 +855,7 @@ int ssl3_get_server_hello(SSL *s)
s->s3->tmp.new_compression=comp;
}
#endif
#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions*/
if (s->version > SSL3_VERSION)
@ -1768,7 +1771,7 @@ int ssl3_get_new_session_ticket(SSL *s)
if (ticklen + 6 != n)
{
al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
goto f_err;
}
if (s->session->tlsext_tick)
@ -1779,7 +1782,7 @@ int ssl3_get_new_session_ticket(SSL *s)
s->session->tlsext_tick = OPENSSL_malloc(ticklen);
if (!s->session->tlsext_tick)
{
SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
goto err;
}
memcpy(s->session->tlsext_tick, p, ticklen);

View file

@ -2083,6 +2083,13 @@ void ssl3_free(SSL *s)
if(s == NULL)
return;
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->client_opaque_prf_input != NULL)
OPENSSL_free(s->s3->client_opaque_prf_input);
if (s->s3->server_opaque_prf_input != NULL)
OPENSSL_free(s->s3->server_opaque_prf_input);
#endif
ssl3_cleanup_key_block(s);
if (s->s3->rbuf.buf != NULL)
OPENSSL_free(s->s3->rbuf.buf);
@ -2115,6 +2122,15 @@ void ssl3_clear(SSL *s)
unsigned char *rp,*wp;
size_t rlen, wlen;
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->client_opaque_prf_input != NULL)
OPENSSL_free(s->s3->client_opaque_prf_input);
s->s3->client_opaque_prf_input = NULL;
if (s->s3->server_opaque_prf_input != NULL)
OPENSSL_free(s->s3->server_opaque_prf_input);
s->s3->server_opaque_prf_input = NULL;
#endif
ssl3_cleanup_key_block(s);
if (s->s3->tmp.ca_names != NULL)
sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
@ -2337,11 +2353,33 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE);
return 0;
}
s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
break;
case SSL_CTRL_SET_TLSEXT_DEBUG_ARG:
s->tlsext_debug_arg=parg;
ret = 1;
break;
#ifdef TLSEXT_TYPE_opaque_prf_input
case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT:
if (larg > 12288) /* actual internal limit is 2^16 for the complete hello message
* (including the cert chain and everything) */
{
SSLerr(SSL_F_SSL3_CTRL, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG);
break;
}
if (s->tlsext_opaque_prf_input != NULL)
OPENSSL_free(s->tlsext_opaque_prf_input);
s->tlsext_opaque_prf_input = BUF_memdup(parg, (size_t)larg);
if (s->tlsext_opaque_prf_input != NULL)
{
s->tlsext_opaque_prf_input_len = (size_t)larg;
ret = 1;
}
else
s->tlsext_opaque_prf_input_len = 0;
break;
#endif
#endif /* !OPENSSL_NO_TLSEXT */
default:
break;
@ -2562,7 +2600,15 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
}
return 1;
}
#ifdef TLSEXT_TYPE_opaque_prf_input
case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG:
ctx->tlsext_opaque_prf_input_callback_arg = parg;
return 1;
#endif
#endif /* !OPENSSL_NO_TLSEXT */
/* A Thawte special :-) */
case SSL_CTRL_EXTRA_CHAIN_CERT:
if (ctx->extra_certs == NULL)
@ -2612,6 +2658,13 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
break;
#ifdef TLSEXT_TYPE_opaque_prf_input
case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB:
ctx->tlsext_opaque_prf_input_callback = (int (*)(SSL *,void *, size_t, void *))fp;
break;
#endif
#endif
default:
return(0);

View file

@ -799,7 +799,12 @@ struct ssl_ctx_st
unsigned char tlsext_tick_key_name[16];
unsigned char tlsext_tick_hmac_key[16];
unsigned char tlsext_tick_aes_key[16];
/* draft-rescorla-tls-opaque-prf-input-00.txt information */
int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg);
void *tlsext_opaque_prf_input_callback_arg;
#endif
#ifndef OPENSSL_NO_PSK
char *psk_identity_hint;
unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
@ -1086,11 +1091,16 @@ struct ssl_st
size_t tlsext_ellipticcurvelist_length;
unsigned char *tlsext_ellipticcurvelist; /* our list */
#endif /* OPENSSL_NO_EC */
/* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */
void *tlsext_opaque_prf_input;
size_t tlsext_opaque_prf_input_len;
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
#define session_ctx ctx
#endif
#endif /* OPENSSL_NO_TLSEXT */
};
#ifdef __cplusplus
@ -1304,6 +1314,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57
#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58
#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62
#endif
#define SSL_session_reused(ssl) \
@ -2009,6 +2022,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_NULL_SSL_METHOD_PASSED 196
#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197
#define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297
#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 327
#define SSL_R_PACKET_LENGTH_TOO_LONG 198
#define SSL_R_PARSE_TLSEXT 227
#define SSL_R_PATH_TOO_LONG 270

View file

@ -443,6 +443,14 @@ typedef struct ssl3_state_st
int in_read_app_data;
/* Opaque PRF input as used for the current handshake.
* These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined
* (otherwise, they are merely present to improve binary compatibility) */
void *client_opaque_prf_input;
size_t client_opaque_prf_input_len;
void *server_opaque_prf_input;
size_t server_opaque_prf_input_len;
struct {
/* actually only needs to be 16+20 */
unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];

View file

@ -249,13 +249,13 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), "SSL_use_RSAPrivateKey_file"},
{ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "SSL_VERIFY_CERT_CHAIN"},
{ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"},
{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"},
{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "TLS1_CERT_VERIFY_MAC"},
{ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "TLS1_CHANGE_CIPHER_STATE"},
{ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), "TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), "TLS1_PREPARE_SERVERHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
{ERR_FUNC(SSL_F_TLS1_PRF), "TLS1_PRF"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
{0,NULL}
@ -399,6 +399,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED),"null ssl method passed"},
{ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
{ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
{ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG),"opaque PRF input too long"},
{ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
{ERR_REASON(SSL_R_PARSE_TLSEXT) ,"parse tlsext"},
{ERR_REASON(SSL_R_PATH_TOO_LONG) ,"path too long"},

View file

@ -542,6 +542,7 @@ void SSL_free(SSL *s)
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);
#endif
if (s->client_CA != NULL)

View file

@ -330,24 +330,30 @@
#define SSL_SSLV3 0x00000002L
#define SSL_TLSV1 SSL_SSLV3 /* for now */
/* Bits for algorithm2 (handshake digests) */
/* Bits for algorithm2 (handshake digests and other extra flags) */
#define SSL_HANDSHAKE_MAC_MD5 0x10
#define SSL_HANDSHAKE_MAC_SHA 0x20
#define SSL_HANDSHAKE_MAC_GOST94 0x40
#define SSL_HANDSHAKE_MAC_DEFAULT (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA)
/* When adding new digest in the ssl_ciph.c and increment SSM_MD_NUM_IDX
* make sure to update this constant too */
#define SSL_MAX_DIGEST 4
#define TLS1_PRF_DGST_SHIFT 8
#define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT)
#define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT)
#define TLS1_PRF_GOST94 (SSL_HANDSHAKE_MAC_GOST94 << TLS1_PRF_DGST_SHIFT)
#define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1)
/* Stream MAC for GOST ciphersuites from cryptopro draft
* (currently this also goes into algorithm2) */
#define TLS1_STREAM_MAC 0x04
/*
* Export and cipher strength information. For each cipher we have to decide
* whether it is exportable or not. This information is likely to change

View file

@ -422,6 +422,25 @@ static void lock_dbg_cb(int mode, int type, const char *file, int line)
}
}
#ifdef TLSEXT_TYPE_opaque_prf_input
struct cb_info_st { void *input; size_t len; int ret; };
struct cb_info_st co1 = { "C", 1, 1 }; /* try to negotiate oqaque PRF input */
struct cb_info_st co2 = { "C", 1, 2 }; /* insist on oqaque PRF input */
struct cb_info_st so1 = { "S", 1, 1 }; /* try to negotiate oqaque PRF input */
struct cb_info_st so2 = { "S", 1, 2 }; /* insist on oqaque PRF input */
int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_)
{
struct cb_info_st *arg = arg_;
if (arg == NULL)
return 1;
if (!SSL_set_tlsext_opaque_prf_input(ssl, arg->input, arg->len))
return 0;
return arg->ret;
}
#endif
int main(int argc, char *argv[])
{
@ -836,6 +855,13 @@ bad:
SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb);
#endif
#ifdef TLSEXT_TYPE_opaque_prf_input
SSL_CTX_set_tlsext_opaque_prf_input_callback(c_ctx, opaque_prf_input_cb);
SSL_CTX_set_tlsext_opaque_prf_input_callback(s_ctx, opaque_prf_input_cb);
SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(c_ctx, &co1); /* or &co2 or NULL */
SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(s_ctx, &so1); /* or &so2 or NULL */
#endif
if (!SSL_CTX_use_certificate_file(s_ctx,server_cert,SSL_FILETYPE_PEM))
{
ERR_print_errors(bio_err);

View file

@ -142,8 +142,14 @@
#include <openssl/hmac.h>
#include <openssl/md5.h>
/* seed1 through seed5 are virtually concatenated */
static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
int sec_len, unsigned char *seed, int seed_len,
int sec_len,
const void *seed1, int seed1_len,
const void *seed2, int seed2_len,
const void *seed3, int seed3_len,
const void *seed4, int seed4_len,
const void *seed5, int seed5_len,
unsigned char *out, int olen)
{
int chunk,n;
@ -159,7 +165,11 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
HMAC_CTX_init(&ctx_tmp);
HMAC_Init_ex(&ctx,sec,sec_len,md, NULL);
HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL);
HMAC_Update(&ctx,seed,seed_len);
if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len);
if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len);
if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len);
if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len);
if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len);
HMAC_Final(&ctx,A1,&A1_len);
n=0;
@ -169,7 +179,11 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL); /* re-init */
HMAC_Update(&ctx,A1,A1_len);
HMAC_Update(&ctx_tmp,A1,A1_len);
HMAC_Update(&ctx,seed,seed_len);
if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len);
if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len);
if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len);
if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len);
if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len);
if (olen > chunk)
{
@ -190,9 +204,15 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
OPENSSL_cleanse(A1,sizeof(A1));
}
/* seed1 through seed5 are virtually concatenated */
static void tls1_PRF(long digest_mask,
unsigned char *label, int label_len,
const unsigned char *sec, int slen, unsigned char *out1,
const void *seed1, int seed1_len,
const void *seed2, int seed2_len,
const void *seed3, int seed3_len,
const void *seed4, int seed4_len,
const void *seed5, int seed5_len,
const unsigned char *sec, int slen,
unsigned char *out1,
unsigned char *out2, int olen)
{
int len,i,idx,count;
@ -200,7 +220,7 @@ static void tls1_PRF(long digest_mask,
long m;
const EVP_MD *md;
/* Count number of digests and divide sec evenly */
/* Count number of digests and partition sec evenly */
count=0;
for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) count++;
@ -215,7 +235,9 @@ static void tls1_PRF(long digest_mask,
SSL_R_UNSUPPORTED_DIGEST_TYPE);
return;
}
tls1_P_hash(md ,S1,len+(slen&1),label,label_len,out2,olen);
tls1_P_hash(md ,S1,len+(slen&1),
seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
out2,olen);
S1+=len;
for (i=0; i<olen; i++)
{
@ -228,20 +250,11 @@ static void tls1_PRF(long digest_mask,
static void tls1_generate_key_block(SSL *s, unsigned char *km,
unsigned char *tmp, int num)
{
unsigned char *p;
unsigned char buf[SSL3_RANDOM_SIZE*2+
TLS_MD_MAX_CONST_SIZE];
p=buf;
memcpy(p,TLS_MD_KEY_EXPANSION_CONST,
TLS_MD_KEY_EXPANSION_CONST_SIZE);
p+=TLS_MD_KEY_EXPANSION_CONST_SIZE;
memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
p+=SSL3_RANDOM_SIZE;
memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
p+=SSL3_RANDOM_SIZE;
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(p-buf),
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
s->s3->server_random,SSL3_RANDOM_SIZE,
s->s3->client_random,SSL3_RANDOM_SIZE,
NULL,0,NULL,0,
s->session->master_key,s->session->master_key_length,
km,tmp,num);
#ifdef KSSL_DEBUG
@ -261,8 +274,7 @@ int tls1_change_cipher_state(SSL *s, int which)
{
static const unsigned char empty[]="";
unsigned char *p,*key_block,*mac_secret;
unsigned char *exp_label,buf[TLS_MD_MAX_CONST_SIZE+
SSL3_RANDOM_SIZE*2];
unsigned char *exp_label;
unsigned char tmp1[EVP_MAX_KEY_LENGTH];
unsigned char tmp2[EVP_MAX_KEY_LENGTH];
unsigned char iv1[EVP_MAX_IV_LENGTH*2];
@ -443,29 +455,22 @@ printf("which = %04X\nmac key=",which);
/* In here I set both the read and write key/iv to the
* same value since only the correct one will be used :-).
*/
p=buf;
memcpy(p,exp_label,exp_label_len);
p+=exp_label_len;
memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
p+=SSL3_RANDOM_SIZE;
memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
p+=SSL3_RANDOM_SIZE;
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(p-buf),key,j,
tmp1,tmp2,EVP_CIPHER_key_length(c));
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
exp_label,exp_label_len,
s->s3->client_random,SSL3_RANDOM_SIZE,
s->s3->server_random,SSL3_RANDOM_SIZE,
NULL,0,NULL,0,
key,j,tmp1,tmp2,EVP_CIPHER_key_length(c));
key=tmp1;
if (k > 0)
{
p=buf;
memcpy(p,TLS_MD_IV_BLOCK_CONST,
TLS_MD_IV_BLOCK_CONST_SIZE);
p+=TLS_MD_IV_BLOCK_CONST_SIZE;
memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
p+=SSL3_RANDOM_SIZE;
memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
p+=SSL3_RANDOM_SIZE;
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,p-buf,empty,0,
iv1,iv2,k*2);
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE,
s->s3->client_random,SSL3_RANDOM_SIZE,
s->s3->server_random,SSL3_RANDOM_SIZE,
NULL,0,NULL,0,
empty,0,iv1,iv2,k*2);
if (client_write)
iv=iv1;
else
@ -767,35 +772,51 @@ int tls1_final_finish_mac(SSL *s,
{
unsigned int i;
EVP_MD_CTX ctx;
unsigned char buf[TLS_MD_MAX_CONST_SIZE+MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
unsigned char buf[2*EVP_MAX_MD_SIZE];
unsigned char *q,buf2[12];
int idx;
long mask;
int err=0;
const EVP_MD *md;
q=buf;
memcpy(q,str,slen);
q+=slen;
EVP_MD_CTX_init(&ctx);
if (s->s3->handshake_buffer)
ssl3_digest_cached_records(s);
for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++) {
if (mask & s->s3->tmp.new_cipher->algorithm2) {
EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]);
EVP_DigestFinal_ex(&ctx,q,&i);
q+=i;
for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++)
{
if (mask & s->s3->tmp.new_cipher->algorithm2)
{
int hashsize = EVP_MD_size(md);
if ((size_t)hashsize > (sizeof buf - (size_t)(q-buf)))
{
/* internal error: 'buf' is too small for this cipersuite! */
err = 1;
}
else
{
EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]);
EVP_DigestFinal_ex(&ctx,q,&i);
if (i != hashsize) /* can't really happen */
err = 1;
q+=i;
}
}
}
}
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(q-buf),
s->session->master_key,s->session->master_key_length,
out,buf2,sizeof buf2);
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0,
s->session->master_key,s->session->master_key_length,
out,buf2,sizeof buf2);
EVP_MD_CTX_cleanup(&ctx);
return sizeof buf2;
if (err)
return 0;
else
return sizeof buf2;
}
int tls1_mac(SSL *ssl, unsigned char *md, int send)
@ -876,23 +897,35 @@ printf("rec=");
int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
int len)
{
unsigned char buf[SSL3_RANDOM_SIZE*2+TLS_MD_MASTER_SECRET_CONST_SIZE];
unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
const void *co = NULL, *so = NULL;
int col = 0, sol = NULL;
#ifdef KSSL_DEBUG
printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
#endif /* KSSL_DEBUG */
/* Setup the stuff to munge */
memcpy(buf,TLS_MD_MASTER_SECRET_CONST,
TLS_MD_MASTER_SECRET_CONST_SIZE);
memcpy(&(buf[TLS_MD_MASTER_SECRET_CONST_SIZE]),
s->s3->client_random,SSL3_RANDOM_SIZE);
memcpy(&(buf[SSL3_RANDOM_SIZE+TLS_MD_MASTER_SECRET_CONST_SIZE]),
s->s3->server_random,SSL3_RANDOM_SIZE);
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->client_opaque_prf_input != NULL && s->s3->server_opaque_prf_input != NULL &&
s->s3->client_opaque_prf_input_len > 0 &&
s->s3->client_opaque_prf_input_len == s->s3->server_opaque_prf_input_len)
{
co = s->s3->client_opaque_prf_input;
col = s->s3->server_opaque_prf_input_len;
so = s->s3->server_opaque_prf_input;
sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */
}
#endif
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
buf,TLS_MD_MASTER_SECRET_CONST_SIZE+SSL3_RANDOM_SIZE*2,p,len,
TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
s->s3->client_random,SSL3_RANDOM_SIZE,
co, col,
s->s3->server_random,SSL3_RANDOM_SIZE,
so, sol,
p,len,
s->session->master_key,buff,sizeof buff);
#ifdef KSSL_DEBUG
printf ("tls1_generate_master_secret() complete\n");
#endif /* KSSL_DEBUG */

View file

@ -284,8 +284,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
+ hostname length
*/
if ((lenmax = limit - p - 9) < 0
|| (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
if ((lenmax = limit - ret - 9) < 0
|| (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
return NULL;
/* extension type and length */
@ -300,15 +300,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
s2n(size_str,ret);
memcpy(ret, s->tlsext_hostname, size_str);
ret+=size_str;
}
#ifndef OPENSSL_NO_EC
if (s->tlsext_ecpointformatlist != NULL)
{
/* Add TLS extension ECPointFormats to the ClientHello message */
long lenmax;
if ((lenmax = limit - p - 5) < 0) return NULL;
if ((lenmax = limit - ret - 5) < 0) return NULL;
if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
if (s->tlsext_ecpointformatlist_length > 255)
{
@ -327,7 +327,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
/* Add TLS extension EllipticCurves to the ClientHello message */
long lenmax;
if ((lenmax = limit - p - 6) < 0) return NULL;
if ((lenmax = limit - ret - 6) < 0) return NULL;
if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
if (s->tlsext_ellipticcurvelist_length > 65532)
{
@ -359,8 +359,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
if (limit - p - 4 - ticklen < 0)
return NULL;
if ((long)(limit - ret - 4 - ticklen) < 0) return NULL;
s2n(TLSEXT_TYPE_session_ticket,ret);
s2n(ticklen,ret);
if (ticklen)
@ -370,6 +369,24 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
}
}
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->client_opaque_prf_input != NULL)
{
size_t col = s->s3->client_opaque_prf_input_len;
if ((long)(limit - ret - 6 - col < 0))
return NULL;
if (col > 0xFFFD) /* can't happen */
return NULL;
s2n(TLSEXT_TYPE_opaque_prf_input, ret);
s2n(col + 2, ret);
s2n(col, ret);
memcpy(ret, s->s3->client_opaque_prf_input, col);
ret += col;
}
#endif
if ((extdatalen = ret-p-2)== 0)
return p;
@ -387,7 +404,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
{
if (limit - p - 4 < 0) return NULL;
if ((long)(limit - ret - 4) < 0) return NULL;
s2n(TLSEXT_TYPE_server_name,ret);
s2n(0,ret);
@ -398,7 +415,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
/* Add TLS extension ECPointFormats to the ServerHello message */
long lenmax;
if ((lenmax = limit - p - 5) < 0) return NULL;
if ((lenmax = limit - ret - 5) < 0) return NULL;
if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
if (s->tlsext_ecpointformatlist_length > 255)
{
@ -419,11 +436,29 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
if (s->tlsext_ticket_expected
&& !(SSL_get_options(s) & SSL_OP_NO_TICKET))
{
if (limit - p - 4 < 0) return NULL;
if ((long)(limit - ret - 4) < 0) return NULL;
s2n(TLSEXT_TYPE_session_ticket,ret);
s2n(0,ret);
}
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->server_opaque_prf_input != NULL)
{
size_t sol = s->s3->server_opaque_prf_input_len;
if ((long)(limit - ret - 6 - sol) < 0)
return NULL;
if (sol > 0xFFFD) /* can't happen */
return NULL;
s2n(TLSEXT_TYPE_opaque_prf_input, ret);
s2n(sol + 2, ret);
s2n(sol, ret);
memcpy(ret, s->s3->server_opaque_prf_input, sol);
ret += sol;
}
#endif
if ((extdatalen = ret-p-2)== 0)
return p;
@ -610,6 +645,35 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
#endif
}
#endif /* OPENSSL_NO_EC */
#ifdef TLSEXT_TYPE_opaque_prf_input
else if (type == TLSEXT_TYPE_opaque_prf_input)
{
unsigned char *sdata = data;
if (size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
n2s(sdata, s->s3->client_opaque_prf_input_len);
if (s->s3->client_opaque_prf_input_len != size - 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
OPENSSL_free(s->s3->client_opaque_prf_input);
s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len);
if (s->s3->client_opaque_prf_input == NULL)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
}
#endif
/* session ticket processed earlier */
data+=size;
}
@ -694,6 +758,35 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
s->tlsext_ticket_expected = 1;
}
#ifdef TLSEXT_TYPE_opaque_prf_input
else if (type == TLSEXT_TYPE_opaque_prf_input)
{
unsigned char *sdata = data;
if (size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
n2s(sdata, s->s3->server_opaque_prf_input_len);
if (s->s3->server_opaque_prf_input_len != size - 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
OPENSSL_free(s->s3->server_opaque_prf_input);
s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len);
if (s->s3->server_opaque_prf_input == NULL)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
}
#endif
data+=size;
}
@ -780,6 +873,38 @@ int ssl_prepare_clienthello_tlsext(SSL *s)
s2n(i,j);
}
#endif /* OPENSSL_NO_EC */
#ifdef TLSEXT_TYPE_opaque_prf_input
{
int r = 1;
if (s->ctx->tlsext_opaque_prf_input_callback != 0)
{
r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
if (!r)
return -1;
}
if (s->tlsext_opaque_prf_input != NULL)
{
if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
OPENSSL_free(s->s3->client_opaque_prf_input);
s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
if (s->s3->client_opaque_prf_input == NULL)
{
SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
return -1;
}
s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
}
if (r == 2)
/* at callback's request, insist on receiving an appropriate server opaque PRF input */
s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
}
#endif
return 1;
}
@ -810,6 +935,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s)
s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
}
#endif /* OPENSSL_NO_EC */
return 1;
}
@ -832,6 +958,62 @@ int ssl_check_clienthello_tlsext(SSL *s)
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);
#ifdef TLSEXT_TYPE_opaque_prf_input
{
/* This sort of belongs into ssl_prepare_serverhello_tlsext(),
* but we might be sending an alert in response to the client hello,
* so this has to happen here in ssl_check_clienthello_tlsext(). */
int r = 1;
if (s->ctx->tlsext_opaque_prf_input_callback != 0)
{
r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
if (!r)
{
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
al = SSL_AD_INTERNAL_ERROR;
goto err;
}
}
if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
OPENSSL_free(s->s3->server_opaque_prf_input);
s->s3->server_opaque_prf_input = NULL;
if (s->tlsext_opaque_prf_input != NULL)
{
if (s->s3->client_opaque_prf_input != NULL &&
s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len)
{
/* can only use this extension if we have a server opaque PRF input
* of the same length as the client opaque PRF input! */
s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
if (s->s3->server_opaque_prf_input == NULL)
{
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
al = SSL_AD_INTERNAL_ERROR;
goto err;
}
s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
}
}
if (r == 2 && s->s3->server_opaque_prf_input == NULL)
{
/* The callback wants to enforce use of the extension,
* but we can't do that with the client opaque PRF input;
* abort the handshake.
*/
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
al = SSL_AD_HANDSHAKE_FAILURE;
}
}
#endif
err:
switch (ret)
{
case SSL_TLSEXT_ERR_ALERT_FATAL:
@ -895,6 +1077,29 @@ int ssl_check_serverhello_tlsext(SSL *s)
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);
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->server_opaque_prf_input_len > 0)
{
/* This case may indicate that we, as a client, want to insist on using opaque PRF inputs.
* So first verify that we really have a value from the server too. */
if (s->s3->server_opaque_prf_input == NULL)
{
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
al = SSL_AD_HANDSHAKE_FAILURE;
}
/* Anytime the server *has* sent an opaque PRF input, we need to check
* that we have a client opaque PRF input of the same size. */
if (s->s3->client_opaque_prf_input == NULL ||
s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len)
{
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
al = SSL_AD_ILLEGAL_PARAMETER;
}
}
#endif
switch (ret)
{
case SSL_TLSEXT_ERR_ALERT_FATAL:

View file

@ -183,16 +183,23 @@ extern "C" {
#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */
/* ExtensionType values from RFC 3546 */
/* ExtensionType values from RFC3546 / RFC4366 */
#define TLSEXT_TYPE_server_name 0
#define TLSEXT_TYPE_max_fragment_length 1
#define TLSEXT_TYPE_client_certificate_url 2
#define TLSEXT_TYPE_trusted_ca_keys 3
#define TLSEXT_TYPE_truncated_hmac 4
#define TLSEXT_TYPE_status_request 5
/* ExtensionType values from RFC4492 */
#define TLSEXT_TYPE_elliptic_curves 10
#define TLSEXT_TYPE_ec_point_formats 11
#define TLSEXT_TYPE_session_ticket 35
/* ExtensionType value from draft-rescorla-tls-opaque-prf-input-00.txt */
#if 0 /* will have to be provided externally for now ,
* i.e. build with -DTLSEXT_TYPE_opaque_prf_input=38183
* using whatever extension number you'd like to try */
# define TLSEXT_TYPE_opaque_prf_input ?? */
#endif
/* NameType value from RFC 3546 */
#define TLSEXT_NAMETYPE_host_name 0
@ -235,6 +242,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLXEXT_TICKET_KEYS,(keylen),(keys))
#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys))
#define SSL_set_tlsext_opaque_prf_input(s, src, len) \
SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT, len, src)
#define SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) \
SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB, (void (*)(void))cb)
#define SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg) \
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg)
#endif
/* PSK ciphersuites from 4279 */
@ -416,10 +431,6 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA"
#define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA"
/* Flags for SSL_CIPHER.algorithm2 field */
/* Stream MAC for GOST ciphersuites from cryptopro draft */
#define TLS1_STREAM_MAC 0x04
#define TLS_CT_RSA_SIGN 1
#define TLS_CT_DSS_SIGN 2