static int get_server_hello(SSL *s) { unsigned char *buf; unsigned char *p; int i,j; unsigned long len; STACK_OF(SSL_CIPHER) *sk=NULL,*cl, *prio, *allow; buf=(unsigned char *)s->init_buf->data; p=buf; if (s->state == SSL2_ST_GET_SERVER_HELLO_A) { i=ssl2_read(s,(char *)&(buf[s->init_num]),11-s->init_num); if (i < (11-s->init_num)) return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i)); s->init_num = 11; if (*(p++) != SSL2_MT_SERVER_HELLO) { if (p[-1] != SSL2_MT_ERROR) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_READ_WRONG_PACKET_TYPE); } else SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_PEER_ERROR); return(-1); } #ifdef __APPLE_CC__ /* The Rhapsody 5.5 (a.k.a. MacOS X) compiler bug * workaround. <*****@*****.**> */ s->hit=(i=*(p++))?1:0; #else s->hit=(*(p++))?1:0; #endif s->s2->tmp.cert_type= *(p++); n2s(p,i); if (i < s->version) s->version=i; n2s(p,i); s->s2->tmp.cert_length=i; n2s(p,i); s->s2->tmp.csl=i; n2s(p,i); s->s2->tmp.conn_id_length=i; s->state=SSL2_ST_GET_SERVER_HELLO_B; } /* SSL2_ST_GET_SERVER_HELLO_B */ len = 11 + (unsigned long)s->s2->tmp.cert_length + (unsigned long)s->s2->tmp.csl + (unsigned long)s->s2->tmp.conn_id_length; if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_MESSAGE_TOO_LONG); return -1; } j = (int)len - s->init_num; i = ssl2_read(s,(char *)&(buf[s->init_num]),j); if (i != j) return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i)); if (s->msg_callback) s->msg_callback(0, s->version, 0, buf, (size_t)len, s, s->msg_callback_arg); /* SERVER-HELLO */ /* things are looking good */ p = buf + 11; if (s->hit) { if (s->s2->tmp.cert_length != 0) { SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_LENGTH_NOT_ZERO); return(-1); } if (s->s2->tmp.cert_type != 0) { if (!(s->options & SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG)) { SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_TYPE_NOT_ZERO); return(-1); } } if (s->s2->tmp.csl != 0) { SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CIPHER_LIST_NOT_ZERO); return(-1); } } else { #ifdef undef /* very bad */ memset(s->session->session_id,0, SSL_MAX_SSL_SESSION_ID_LENGTH_IN_BYTES); s->session->session_id_length=0; */ #endif /* we need to do this in case we were trying to reuse a * client session but others are already reusing it. * If this was a new 'blank' session ID, the session-id * length will still be 0 */ if (s->session->session_id_length > 0) { if (!ssl_get_new_session(s,0)) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); return(-1); } } if (ssl2_set_certificate(s,s->s2->tmp.cert_type, s->s2->tmp.cert_length,p) <= 0) { ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE); return(-1); } p+=s->s2->tmp.cert_length; if (s->s2->tmp.csl == 0) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_LIST); return(-1); } /* We have just received a list of ciphers back from the * server. We need to get the ones that match, then select * the one we want the most :-). */ /* load the ciphers */ sk=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.csl, &s->session->ciphers); p+=s->s2->tmp.csl; if (sk == NULL) { ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO,ERR_R_MALLOC_FAILURE); return(-1); } (void)sk_SSL_CIPHER_set_cmp_func(sk,ssl_cipher_ptr_id_cmp); /* get the array of ciphers we will accept */ cl=SSL_get_ciphers(s); (void)sk_SSL_CIPHER_set_cmp_func(cl,ssl_cipher_ptr_id_cmp); /* * If server preference flag set, choose the first * (highest priority) cipher the server sends, otherwise * client preference has priority. */ if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { prio = sk; allow = cl; } else { prio = cl; allow = sk; } /* In theory we could have ciphers sent back that we * don't want to use but that does not matter since we * will check against the list we originally sent and * for performance reasons we should not bother to match * the two lists up just to check. */ for (i=0; i<sk_SSL_CIPHER_num(prio); i++) { if (sk_SSL_CIPHER_find(allow, sk_SSL_CIPHER_value(prio,i)) >= 0) break; } if (i >= sk_SSL_CIPHER_num(prio)) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_MATCH); return(-1); } s->session->cipher=sk_SSL_CIPHER_value(prio,i); if (s->session->peer != NULL) /* can't happen*/ { ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); return(-1); } s->session->peer = s->session->sess_cert->peer_key->x509; /* peer_key->x509 has been set by ssl2_set_certificate. */ CRYPTO_add(&s->session->peer->references, 1, CRYPTO_LOCK_X509); } if (s->session->sess_cert == NULL || s->session->peer != s->session->sess_cert->peer_key->x509) /* can't happen */ { ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); return(-1); } s->s2->conn_id_length=s->s2->tmp.conn_id_length; if (s->s2->conn_id_length > sizeof s->s2->conn_id) { ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_SSL2_CONNECTION_ID_TOO_LONG); return -1; } memcpy(s->s2->conn_id,p,s->s2->tmp.conn_id_length); return(1); }
#define N_CIPHERS (sizeof(cipher_bytes) / 2) extern STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const unsigned char *p, int num); extern int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, unsigned char *p); static int ssl_bytes_to_list_alloc(SSL *s, STACK_OF(SSL_CIPHER) **ciphers) { SSL_CIPHER *cipher; uint16_t value; int i; *ciphers = ssl_bytes_to_cipher_list(s, cipher_bytes, sizeof(cipher_bytes)); CHECK(*ciphers != NULL); CHECK(sk_SSL_CIPHER_num(*ciphers) == N_CIPHERS); for (i = 0; i < sk_SSL_CIPHER_num(*ciphers); i++) { cipher = sk_SSL_CIPHER_value(*ciphers, i); CHECK(cipher != NULL); value = SSL_CIPHER_get_value(cipher); CHECK(value == cipher_values[i]); } return 1; } static int ssl_list_to_bytes_scsv(SSL *s, STACK_OF(SSL_CIPHER) **ciphers) {