diff --git a/CHANGES b/CHANGES index f220bbe15e9dc0204c8d2b1e194efd048085a078..cc2d55f80cce23651d4d1b776671edc94ce1ecda 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,12 @@ Changes between 0.9.8a and 0.9.9 [xx XXX xxxx] + *) New option SSL_OP_NO_COMP to disable use of compression selectively + in SSL structures. New SSL ctrl to set maximum send fragment size. + Save memory by seeting the I/O buffer sizes dynamically instead of + using the maximum available value. + [Steve Henson] + *) New option -V for 'openssl ciphers'. This prints the ciphersuite code in addition to the text details. [Bodo Moeller] diff --git a/apps/s_client.c b/apps/s_client.c index 96ae832ca1a78a84be4913ae1a0b545b5a5e4ebb..efd8b06fe6eea310ecccff3c1b111d0fb665f6d6 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -450,6 +450,8 @@ int MAIN(int argc, char **argv) off|=SSL_OP_NO_SSLv3; else if (strcmp(*argv,"-no_ssl2") == 0) off|=SSL_OP_NO_SSLv2; + else if (strcmp(*argv,"-no_comp") == 0) + { off|=SSL_OP_NO_COMPRESSION; } else if (strcmp(*argv,"-serverpref") == 0) off|=SSL_OP_CIPHER_SERVER_PREFERENCE; else if (strcmp(*argv,"-cipher") == 0) diff --git a/apps/s_server.c b/apps/s_server.c index 8c6fcc240ad357ef3c2684d12f565b37bd95b919..27c0e43fb4a6bb56fad41b8aedd3dcf9c855aff2 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -754,6 +754,8 @@ int MAIN(int argc, char *argv[]) { off|=SSL_OP_NO_SSLv3; } else if (strcmp(*argv,"-no_tls1") == 0) { off|=SSL_OP_NO_TLSv1; } + else if (strcmp(*argv,"-no_comp") == 0) + { off|=SSL_OP_NO_COMPRESSION; } #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv,"-ssl2") == 0) { meth=SSLv2_server_method(); } diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index 045a953ce4e0148d70bb37c95e80d69eeb737292..3cbc64257074b3586b7b68c95091528de88b8762 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -349,7 +349,8 @@ static int ssl23_client_hello(SSL *s) p+=i; /* COMPRESSION */ - if (s->ctx->comp_methods == NULL) + if ((s->options & SSL_OP_NO_COMPRESSION) + || !s->ctx->comp_methods) j=0; else j=sk_SSL_COMP_num(s->ctx->comp_methods); diff --git a/ssl/s3_both.c b/ssl/s3_both.c index 2ecfbb77cb1704bda84a57110a3256af1f568daa..09d72e545d7b24ac5e2bcf8652f0ecab6e3fed93 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c @@ -589,16 +589,22 @@ int ssl_verify_alarm_type(long type) int ssl3_setup_buffers(SSL *s) { unsigned char *p; - unsigned int extra; size_t len; if (s->s3->rbuf.buf == NULL) { + len = SSL3_RT_MAX_PLAIN_LENGTH + + SSL3_RT_MAX_ENCRYPTED_OVERHEAD + + SSL3_RT_HEADER_LENGTH; if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) - extra=SSL3_RT_MAX_EXTRA; - else - extra=0; - len = SSL3_RT_MAX_PACKET_SIZE + extra; + { + s->s3->init_extra = 1; + len += SSL3_RT_MAX_EXTRA; + } +#ifndef OPENSSL_NO_COMP + if (!(s->options & SSL_OP_NO_COMPRESSION)) + len += SSL3_RT_MAX_COMPRESSED_OVERHEAD; +#endif if ((p=OPENSSL_malloc(len)) == NULL) goto err; s->s3->rbuf.buf = p; @@ -607,8 +613,16 @@ int ssl3_setup_buffers(SSL *s) if (s->s3->wbuf.buf == NULL) { - len = SSL3_RT_MAX_PACKET_SIZE; - len += SSL3_RT_HEADER_LENGTH + 256; /* extra space for empty fragment */ + len = s->max_send_fragment + + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + + SSL3_RT_HEADER_LENGTH; +#ifndef OPENSSL_NO_COMP + if (!(s->options & SSL_OP_NO_COMPRESSION)) + len += SSL3_RT_MAX_COMPRESSED_OVERHEAD; +#endif + if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) + len += SSL3_RT_HEADER_LENGTH + + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; if ((p=OPENSSL_malloc(len)) == NULL) goto err; s->s3->wbuf.buf = p; diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index cc9df9186dd8daf382f97c7fdf0d2c647402a39e..7284c0aa4b95afc20dc200759fc0e4962070406c 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -588,7 +588,9 @@ int ssl3_client_hello(SSL *s) #ifdef OPENSSL_NO_COMP *(p++)=1; #else - if (s->ctx->comp_methods == NULL) + + if ((s->options & SSL_OP_NO_COMPRESSION) + || !s->ctx->comp_methods) j=0; else j=sk_SSL_COMP_num(s->ctx->comp_methods); @@ -768,7 +770,7 @@ int ssl3_get_server_hello(SSL *s) } #else j= *(p++); - if (j == 0) + if ((j == 0) || (s->options & SSL_OP_NO_COMPRESSION)) comp=NULL; else comp=ssl3_comp_find(s->ctx->comp_methods,j); diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index d0f54e297bb7af5e53ff732363c5c6c85b530dd4..fc913c2d9e69b96ba02fef7b3015c9f547afc8c3 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -250,9 +250,9 @@ static int ssl3_get_record(SSL *s) extra=SSL3_RT_MAX_EXTRA; else extra=0; - if (extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE) + if (extra && !s->s3->init_extra) { - /* actually likely an application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER + /* An application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER * set after ssl3_setup_buffers() was done */ SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR); return -1; @@ -275,6 +275,9 @@ again: ssl_minor= *(p++); version=(ssl_major<<8)|ssl_minor; n2s(p,rr->length); +#if 0 +fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length); +#endif /* Lets check version */ if (s->first_packet) @@ -300,7 +303,7 @@ again: goto err; } - if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH+extra) + if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH) { al=SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG); @@ -466,6 +469,10 @@ printf("\n"); /* just read a 0 length packet */ if (rr->length == 0) goto again; +#if 0 +fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, rr->length); +#endif + return(1); f_err: @@ -539,8 +546,8 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) n=(len-tot); for (;;) { - if (n > SSL3_RT_MAX_PLAIN_LENGTH) - nw=SSL3_RT_MAX_PLAIN_LENGTH; + if (n > s->max_send_fragment) + nw=s->max_send_fragment; else nw=n; @@ -624,7 +631,8 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, if (prefix_len <= 0) goto err; - if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE) + if (prefix_len > + (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) { /* insufficient space */ SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR); diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 775bac34890f5b43d594a3ca43557ce40518452a..96a2602d07d4bae27e6f8f8d55228f9ca40a86fc 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -900,7 +900,7 @@ int ssl3_get_client_hello(SSL *s) * algorithms from the client, starting at q. */ s->s3->tmp.new_compression=NULL; #ifndef OPENSSL_NO_COMP - if (s->ctx->comp_methods != NULL) + if (!(s->options & SSL_OP_NO_COMPRESSION) && s->ctx->comp_methods) { /* See if we have a match */ int m,nn,o,v,done=0; diff --git a/ssl/ssl.h b/ssl/ssl.h index f06b06994f29401c92ac7840e52cefe58f650b79..120c7a30ebfdd1825c82e3eec9645bfe490c0ff4 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -503,6 +503,8 @@ typedef struct ssl_session_st /* As server, disallow session resumption on renegotiation */ #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L +/* Don't use compression even if supported */ +#define SSL_OP_NO_COMPRESSION 0x00020000L /* If set, always create a new key when using tmp_ecdh parameters */ #define SSL_OP_SINGLE_ECDH_USE 0x00080000L /* If set, always create a new key when using tmp_dh parameters */ @@ -747,6 +749,12 @@ struct ssl_ctx_st #endif int quiet_shutdown; + + /* Maximum amount of data to send in one fragment. + * actual record size can be more than this due to + * padding and MAC overheads. + */ + int max_send_fragment; }; #define SSL_SESS_CACHE_OFF 0x0000 @@ -968,6 +976,7 @@ struct ssl_st int first_packet; int client_version; /* what was passed, used for * SSLv3/TLS rollback check */ + int max_send_fragment; }; #ifdef __cplusplus @@ -1171,6 +1180,8 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count); #define SSL_CTRL_GET_MAX_CERT_LIST 50 #define SSL_CTRL_SET_MAX_CERT_LIST 51 +#define SSL_CTRL_SET_MAX_SEND_FRAGMENT 52 + #define SSL_session_reused(ssl) \ SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL) #define SSL_num_renegotiations(ssl) \ @@ -1492,6 +1503,11 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void ); #define SSL_set_max_cert_list(ssl,m) \ SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) +#define SSL_CTX_set_max_send_fragment(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL) +#define SSL_set_max_send_fragment(ssl,m) \ + SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL) + /* NB: the keylength is only applicable when is_export is true */ #ifndef OPENSSL_NO_RSA void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, diff --git a/ssl/ssl3.h b/ssl/ssl3.h index f0fbf8275b4383fedbd09797d96c76dc3442bf78..2c6c79bf664805733db7ac27ad3f1e8b48910899 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -244,6 +244,18 @@ extern "C" { #define SSL3_SESSION_ID_SIZE 32 #define SSL3_RT_HEADER_LENGTH 5 +/* This is the maximum MAC (digest) size used by the SSL library. + * Currently this is 20 when SHA1 is used. This must be updated if larger + * digests are used in future. + */ + +#define SSL3_RT_MAX_MD_SIZE 20 + +/* Maximum block size used in all ciphersuites. Currently 16 for AES. + */ + +#define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16 + /* Due to MS stuffing up, this can change.... */ #if defined(OPENSSL_SYS_WIN16) || \ (defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)) @@ -252,14 +264,36 @@ extern "C" { #define SSL3_RT_MAX_EXTRA (16384) #endif +/* Maximum plaintext length: defined by SSL/TLS standards */ #define SSL3_RT_MAX_PLAIN_LENGTH 16384 +/* Maximum compression overhead: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024 + +/* The standards give a maximum encryption overhead of 1024 bytes. + * In practice the value is lower than this. The overhead is the maximum + * number of padding bytes (256) plus the mac size. + */ +#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE) + +/* OpenSSL currently only uses a padding length of at most one block so + * the send overhead is smaller. + */ + +#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \ + (SSL_RT_MAX_CIPHER_BLOCK_SIZE + SSL3_RT_MAX_MD_SIZE) + +/* If compression isn't used don't include the compression overhead */ + #ifdef OPENSSL_NO_COMP -#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH +#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH #else -#define SSL3_RT_MAX_COMPRESSED_LENGTH (1024+SSL3_RT_MAX_PLAIN_LENGTH) +#define SSL3_RT_MAX_COMPRESSED_LENGTH \ + (SSL3_RT_MAX_PLAIN_LENGTH+SSL3_RT_MAX_COMPRESSED_OVERHEAD) #endif -#define SSL3_RT_MAX_ENCRYPTED_LENGTH (1024+SSL3_RT_MAX_COMPRESSED_LENGTH) -#define SSL3_RT_MAX_PACKET_SIZE (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH) +#define SSL3_RT_MAX_ENCRYPTED_LENGTH \ + (SSL3_RT_MAX_ENCRYPTED_OVERHEAD+SSL3_RT_MAX_COMPRESSED_LENGTH) +#define SSL3_RT_MAX_PACKET_SIZE \ + (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH) #define SSL3_RT_MAX_DATA_SIZE (1024*1024) #define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54" @@ -347,6 +381,9 @@ typedef struct ssl3_state_st int need_empty_fragments; int empty_fragment_done; + /* The value of 'extra' when the buffers were initialized */ + int init_extra; + SSL3_BUFFER rbuf; /* read IO goes into here */ SSL3_BUFFER wbuf; /* write IO goes into here */ diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 6fb9364bea120c7b3b99de3647dc59b6cbfac1b2..f524f630d0727c1c8b5d931ead3b875af1bcbe8d 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -303,6 +303,7 @@ SSL *SSL_new(SSL_CTX *ctx) s->trust = ctx->trust; #endif s->quiet_shutdown=ctx->quiet_shutdown; + s->max_send_fragment = ctx->max_send_fragment; CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); s->ctx=ctx; @@ -973,6 +974,11 @@ long SSL_ctrl(SSL *s,int cmd,long larg,void *parg) return larg; } return 0; + case SSL_CTRL_SET_MAX_SEND_FRAGMENT: + if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH) + return 0; + s->max_send_fragment = larg; + return 1; default: return(s->method->ssl_ctrl(s,cmd,larg,parg)); } @@ -1061,6 +1067,11 @@ long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,void *parg) return(ctx->options|=larg); case SSL_CTRL_MODE: return(ctx->mode|=larg); + case SSL_CTRL_SET_MAX_SEND_FRAGMENT: + if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH) + return 0; + ctx->max_send_fragment = larg; + return 1; default: return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg)); } @@ -1453,6 +1464,8 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) ret->extra_certs=NULL; ret->comp_methods=SSL_COMP_get_compression_methods(); + ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH; + return(ret); err: SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);