+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+static const unsigned char ssl3_pad_1[48] = {
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
+};
+
+static const unsigned char ssl3_pad_2[48] = {
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
+};
+
+static int ssl3_handshake_mac(SSL *s, int md_nid,
+ const char *sender, int len, unsigned char *p);
+static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num)
+{
+ EVP_MD_CTX m5;
+ EVP_MD_CTX s1;
+ unsigned char buf[16], smd[SHA_DIGEST_LENGTH];
+ unsigned char c = 'A';
+ unsigned int i, j, k;
+
+#ifdef CHARSET_EBCDIC
+ c = os_toascii[c]; /* 'A' in ASCII */
+#endif
+ k = 0;
+ EVP_MD_CTX_init(&m5);
+ EVP_MD_CTX_set_flags(&m5, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ EVP_MD_CTX_init(&s1);
+ for (i = 0; (int)i < num; i += MD5_DIGEST_LENGTH) {
+ k++;
+ if (k > sizeof buf) {
+ /* bug: 'buf' is too small for this ciphersuite */
+ SSLerr(SSL_F_SSL3_GENERATE_KEY_BLOCK, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ for (j = 0; j < k; j++)
+ buf[j] = c;
+ c++;
+ EVP_DigestInit_ex(&s1, EVP_sha1(), NULL);
+ EVP_DigestUpdate(&s1, buf, k);
+ EVP_DigestUpdate(&s1, s->session->master_key,
+ s->session->master_key_length);
+ EVP_DigestUpdate(&s1, s->s3->server_random, SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&s1, s->s3->client_random, SSL3_RANDOM_SIZE);
+ EVP_DigestFinal_ex(&s1, smd, NULL);
+
+ EVP_DigestInit_ex(&m5, EVP_md5(), NULL);
+ EVP_DigestUpdate(&m5, s->session->master_key,
+ s->session->master_key_length);
+ EVP_DigestUpdate(&m5, smd, SHA_DIGEST_LENGTH);
+ if ((int)(i + MD5_DIGEST_LENGTH) > num) {
+ EVP_DigestFinal_ex(&m5, smd, NULL);
+ memcpy(km, smd, (num - i));
+ } else
+ EVP_DigestFinal_ex(&m5, km, NULL);
+
+ km += MD5_DIGEST_LENGTH;
+ }
+ OPENSSL_cleanse(smd, sizeof(smd));
+ EVP_MD_CTX_cleanup(&m5);
+ EVP_MD_CTX_cleanup(&s1);
+ return 1;
+}
+
+int ssl3_change_cipher_state(SSL *s, int which)
+{
+ unsigned char *p, *mac_secret;
+ unsigned char exp_key[EVP_MAX_KEY_LENGTH];
+ unsigned char exp_iv[EVP_MAX_IV_LENGTH];
+ unsigned char *ms, *key, *iv, *er1, *er2;
+ EVP_CIPHER_CTX *dd;
+ const EVP_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
+ COMP_METHOD *comp;
+#endif
+ const EVP_MD *m;
+ EVP_MD_CTX md;
+ int is_exp, n, i, j, k, cl;
+ int reuse_dd = 0;
+
+ is_exp = SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
+ c = s->s3->tmp.new_sym_enc;
+ m = s->s3->tmp.new_hash;
+ /* m == NULL will lead to a crash later */
+ OPENSSL_assert(m);
+#ifndef OPENSSL_NO_COMP
+ if (s->s3->tmp.new_compression == NULL)
+ comp = NULL;
+ else
+ comp = s->s3->tmp.new_compression->method;
+#endif
+
+ if (which & SSL3_CC_READ) {
+ if (s->enc_read_ctx != NULL)
+ reuse_dd = 1;
+ else if ((s->enc_read_ctx =
+ OPENSSL_malloc(sizeof(*s->enc_read_ctx))) == NULL)
+ goto err;
+ else
+ /*
+ * make sure it's intialized in case we exit later with an error
+ */
+ EVP_CIPHER_CTX_init(s->enc_read_ctx);
+ dd = s->enc_read_ctx;
+
+ if (!ssl_replace_hash(&s->read_hash, m)) {
+ SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+ goto err2;
+ }
+#ifndef OPENSSL_NO_COMP
+ /* COMPRESS */
+ COMP_CTX_free(s->expand);
+ s->expand = NULL;
+ if (comp != NULL) {
+ s->expand = COMP_CTX_new(comp);
+ if (s->expand == NULL) {
+ SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE,
+ SSL_R_COMPRESSION_LIBRARY_ERROR);
+ goto err2;
+ }
+ if (!RECORD_LAYER_setup_comp_buffer(&s->rlayer))
+ goto err;
+ }
+#endif
+ RECORD_LAYER_reset_read_sequence(&s->rlayer);
+ mac_secret = &(s->s3->read_mac_secret[0]);
+ } else {
+ if (s->enc_write_ctx != NULL)
+ reuse_dd = 1;
+ else if ((s->enc_write_ctx =
+ OPENSSL_malloc(sizeof(*s->enc_write_ctx))) == NULL)
+ goto err;
+ else
+ /*
+ * make sure it's intialized in case we exit later with an error
+ */
+ EVP_CIPHER_CTX_init(s->enc_write_ctx);
+ dd = s->enc_write_ctx;
+ if (!ssl_replace_hash(&s->write_hash, m)) {
+ SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+ goto err2;
+ }
+#ifndef OPENSSL_NO_COMP
+ /* COMPRESS */
+ COMP_CTX_free(s->compress);
+ s->compress = NULL;
+ if (comp != NULL) {
+ s->compress = COMP_CTX_new(comp);
+ if (s->compress == NULL) {
+ SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE,
+ SSL_R_COMPRESSION_LIBRARY_ERROR);
+ goto err2;
+ }
+ }
+#endif
+ RECORD_LAYER_reset_write_sequence(&s->rlayer);
+ mac_secret = &(s->s3->write_mac_secret[0]);
+ }
+
+ if (reuse_dd)
+ EVP_CIPHER_CTX_cleanup(dd);
+
+ p = s->s3->tmp.key_block;
+ i = EVP_MD_size(m);
+ if (i < 0)
+ goto err2;
+ cl = EVP_CIPHER_key_length(c);
+ j = is_exp ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
+ cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
+ /* Was j=(is_exp)?5:EVP_CIPHER_key_length(c); */
+ k = EVP_CIPHER_iv_length(c);
+ if ((which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
+ (which == SSL3_CHANGE_CIPHER_SERVER_READ)) {
+ ms = &(p[0]);
+ n = i + i;
+ key = &(p[n]);
+ n += j + j;
+ iv = &(p[n]);
+ n += k + k;
+ er1 = &(s->s3->client_random[0]);
+ er2 = &(s->s3->server_random[0]);
+ } else {
+ n = i;
+ ms = &(p[n]);
+ n += i + j;
+ key = &(p[n]);
+ n += j + k;
+ iv = &(p[n]);
+ n += k;
+ er1 = &(s->s3->server_random[0]);
+ er2 = &(s->s3->client_random[0]);
+ }
+
+ if (n > s->s3->tmp.key_block_length) {
+ SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+ goto err2;
+ }
+
+ EVP_MD_CTX_init(&md);
+ memcpy(mac_secret, ms, i);
+ if (is_exp) {
+ /*
+ * In here I set both the read and write key/iv to the same value
+ * since only the correct one will be used :-).
+ */
+ EVP_DigestInit_ex(&md, EVP_md5(), NULL);
+ EVP_DigestUpdate(&md, key, j);
+ EVP_DigestUpdate(&md, er1, SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md, er2, SSL3_RANDOM_SIZE);
+ EVP_DigestFinal_ex(&md, &(exp_key[0]), NULL);
+ key = &(exp_key[0]);
+
+ if (k > 0) {
+ EVP_DigestInit_ex(&md, EVP_md5(), NULL);
+ EVP_DigestUpdate(&md, er1, SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md, er2, SSL3_RANDOM_SIZE);
+ EVP_DigestFinal_ex(&md, &(exp_iv[0]), NULL);
+ iv = &(exp_iv[0]);
+ }
+ }
+
+ EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE));
+
+#ifdef OPENSSL_SSL_TRACE_CRYPTO
+ if (s->msg_callback) {
+
+ int wh = which & SSL3_CC_WRITE ?
+ TLS1_RT_CRYPTO_WRITE : TLS1_RT_CRYPTO_READ;
+ s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_MAC,
+ mac_secret, EVP_MD_size(m), s, s->msg_callback_arg);
+ if (c->key_len)
+ s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_KEY,
+ key, c->key_len, s, s->msg_callback_arg);
+ if (k) {
+ s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_IV,
+ iv, k, s, s->msg_callback_arg);
+ }
+ }
+#endif