void dtls1_stop_timer(SSL *s) { /* Reset everything */ memset(&s->d1->timeout, 0, sizeof(s->d1->timeout)); memset(&s->d1->next_timeout, 0, sizeof(s->d1->next_timeout)); s->d1->timeout_duration = 1; BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout)); /* Clear retransmission buffer */ dtls1_clear_record_buffer(s); }
int dtls1_listen(SSL *s, struct sockaddr *client) { int ret; SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE); s->d1->listen = 1; ret = SSL_accept(s); if (ret <= 0) return ret; (void) BIO_dgram_get_peer(SSL_get_rbio(s), client); return 1; }
void dtls1_start_timer(SSL *s) { /* If timer is not set, initialize duration with 1 second */ if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) { s->d1->timeout_duration = 1; } /* Set timeout to current time */ get_current_time(s, &s->d1->next_timeout); /* Add duration to current time */ s->d1->next_timeout.tv_sec += s->d1->timeout_duration; BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &s->d1->next_timeout); }
PUBLIC void sslFree(Webs *wp) { BIO *bio; /* Re-use sessions */ if (wp->ssl != NULL) { SSL_set_shutdown(wp->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); } if ((bio = SSL_get_rbio(wp->ssl)) != 0) { BIO_free_all(bio); } }
bool BaseSSLProtocol::SignalInputData(IOBuffer &buffer) { //1. get the SSL input buffer BIO *pInBio = SSL_get_rbio(_pSSL); //2. dump all the data from the network inside the ssl input BIO_write(pInBio, GETIBPOINTER(buffer), GETAVAILABLEBYTESCOUNT(buffer)); buffer.IgnoreAll(); //3. Do we have to do some handshake? if (!_sslHandshakeCompleted) { if (!DoHandshake()) { FATAL("Unable to do the SSL handshake"); return false; } if (!_sslHandshakeCompleted) { return true; } } //4. Read the actual data an put it in the descrypted input buffer int32_t read = 0; while ((read = SSL_read(_pSSL, _pReadBuffer, MAX_SSL_READ_BUFFER)) > 0) { _inputBuffer.ReadFromBuffer(_pReadBuffer, (uint32_t) read); } if (read < 0) { int32_t error = SSL_get_error(_pSSL, read); if (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE) { FATAL("Unable to read data: %d", error); return false; } } //6. If we have pending data inside the decrypted buffer, bubble it up on the protocol stack if (GETAVAILABLEBYTESCOUNT(_inputBuffer) > 0) { if (_pNearProtocol != NULL) { if (!_pNearProtocol->SignalInputData(_inputBuffer)) { FATAL("Unable to signal near protocol for new data"); return false; } } } //7. After the data was sent on the upper layers, we might have outstanding //data that needs to be sent. return PerformIO(); }
int lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd) { #if !defined(USE_WOLFSSL) BIO *bio; #endif errno = 0; wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_ctx); if (wsi->tls.ssl == NULL) { lwsl_err("SSL_new failed: %d (errno %d)\n", lws_ssl_get_error(wsi, 0), errno); lws_tls_err_describe(); return 1; } SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index, wsi); SSL_set_fd(wsi->tls.ssl, (int)(long long)accept_fd); #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->tls.ssl, 1); #else wolfSSL_set_using_nonblock(wsi->tls.ssl, 1); #endif #else SSL_set_mode(wsi->tls.ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_RELEASE_BUFFERS); bio = SSL_get_rbio(wsi->tls.ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(wsi->tls.ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #endif #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) if (wsi->vhost->tls.ssl_info_event_mask) SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback); #endif return 0; }
void ssl_write_ssl(FILE * fp, SSL * ssl) { BIO *bio; SSL_CIPHER *cipher; bio = SSL_get_rbio(ssl); cipher = SSL_CIPHER_get_current_cipher(ssl); fwrite(bio, sizeof(BIO), 1, fp); fwrite(ssl->version, sizeof(ssl->version), 1, fp); fwrite(ssl->type, sizeof(ssl->type), 1, fp); fwrite(ssl->rwstate, sizeof(ssl->type), 1, fp); fwrite(ssl->rstate, sizeof(ssl->type), 1, fp); fwrite(ssl->state, sizeof(ssl->type), 1, fp); fwrite(cipher, sizeof(cipher), 1, fp); }
int dtls1_listen(SSL *s, struct sockaddr *client) { int ret; /* Ensure there is no state left over from a previous invocation */ SSL_clear(s); SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE); s->d1->listen = 1; ret = SSL_accept(s); if (ret <= 0) return ret; (void) BIO_dgram_get_peer(SSL_get_rbio(s), client); return 1; }
CAMLprim value ocaml_ssl_get_rbio_eof(value socket) { CAMLparam1(socket); CAMLlocal1(ret); BIO *b; int eof; ssl_socket_t *ssl = ssl_socket_of_block(socket); b = SSL_get_rbio(ssl->handler); if (b == NULL) failwith("Ssl.get_rbio_eof: No rbio found"); eof = BIO_eof(b); ret = Val_bool(eof); CAMLreturn(ret); }
static int handshake (struct stream_data *data) { int ret; int finished; SSL_library_init(); SSL_load_error_strings(); data->ssl_ctx = SSL_CTX_new(TLSv1_method()); if(!data->ssl_ctx) return IKS_NOMEM; data->ssl = SSL_new(data->ssl_ctx); if(!data->ssl) return IKS_NOMEM; if( SSL_set_fd(data->ssl, (int)(intptr_t)data->sock) != 1 ) return IKS_NOMEM; /* Set both the read and write BIO's to non-blocking mode */ BIO_set_nbio(SSL_get_rbio(data->ssl), 1); BIO_set_nbio(SSL_get_wbio(data->ssl), 1); finished = 0; do { ret = SSL_connect(data->ssl); if( ret != 1 ) { if( wait_for_data(data, ret, 1) != IKS_OK ) { finished = 1; SSL_free(data->ssl); } } } while( ret != 1 && finished != 1 ); if( ret == 1 ) { data->flags &= (~SF_TRY_SECURE); data->flags |= SF_SECURE; iks_send_header (data->prs, data->server); } return ret == 1 ? IKS_OK : IKS_NET_TLSFAIL; }
int ssl_decrypt(SSL *s, const char *in, int len, char **out) { int i; // WARNING: we expect this to be a memory bio... BIO *rbio = SSL_get_rbio(s); if (!BIO_eof(rbio)) { fprintf(stderr, "ssl_decrypt: Someone left data in the rbio!"); fflush(stderr); return -1; } if (BIO_write(rbio, in, len) != len) { fprintf(stderr, "ssl_decrypt: couldn't write to BIO!"); fflush(stderr); return -1; } *out = malloc(len); if (!*out) { return -1; } i = 0; int ret = SSL_read(s, *out + i, len - i); i += ret; // If <= 0, we return it; o.w. we should accumulate. //fprintf(stderr, "first SSL_read returned: %d\n", ret); //fflush(stderr); while (ret > 0 && !BIO_eof(rbio) && i < len) { ret = SSL_read(s, *out + i, len - i); fprintf(stderr, "SSL_read returned: %d\n", ret); fflush(stderr); if (ret > 0) i += ret; } if (!BIO_eof(rbio)) { fprintf(stderr, "We are leaving data in the rbio! ret: %d\n", ret); fprintf(stderr, "In particular, this data:\n"); char *data; long data_len = BIO_get_mem_data(rbio, &data); //hexdump(data, data_len); } return i; }
static SSL_SESSION *on_async_resumption_get(SSL *ssl, unsigned char *data, int len, int *copy) { h2o_socket_t *sock = SSL_get_rbio(ssl)->ptr; switch (sock->ssl->handshake.server.async_resumption.state) { case ASYNC_RESUMPTION_STATE_RECORD: sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_REQUEST_SENT; resumption_get_async(sock, h2o_iovec_init(data, len)); return NULL; case ASYNC_RESUMPTION_STATE_COMPLETE: *copy = 1; return sock->ssl->handshake.server.async_resumption.session_data; default: assert(!"FIXME"); return NULL; } }
int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len) { unsigned char *buffer, result[EVP_MAX_MD_SIZE]; unsigned int length, resultlength; struct sockaddr_in peer; /* Initialize a random secret */ if (!cookie_initialized) { if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH)) { BIO_printf(bio_err,"error setting random cookie secret\n"); return 0; } cookie_initialized = 1; } /* Read peer information */ (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); /* Create buffer with peer's address and port */ length = sizeof(peer.sin_addr); length += sizeof(peer.sin_port); buffer = OPENSSL_malloc(length); if (buffer == NULL) { BIO_printf(bio_err,"out of memory\n"); return 0; } memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr)); memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port)); /* Calculate HMAC of buffer using the secret */ HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, buffer, length, result, &resultlength); OPENSSL_free(buffer); memcpy(cookie, result, resultlength); *cookie_len = resultlength; return 1; }
static int conn_init_client_ssl(Connection *ret, Octstr *certkeyfile) { ret->ssl = SSL_new(global_ssl_context); /* * The current thread's error queue must be empty before * the TLS/SSL I/O operation is attempted, or SSL_get_error() * will not work reliably. */ ERR_clear_error(); if (certkeyfile != NULL) { SSL_use_certificate_file(ret->ssl, octstr_get_cstr(certkeyfile), SSL_FILETYPE_PEM); SSL_use_PrivateKey_file(ret->ssl, octstr_get_cstr(certkeyfile), SSL_FILETYPE_PEM); if (SSL_check_private_key(ret->ssl) != 1) { error(0, "conn_open_ssl: private key isn't consistent with the " "certificate from file %s (or failed reading the file)", octstr_get_cstr(certkeyfile)); return -1; } } /* SSL_set_fd can fail, so check it */ if (SSL_set_fd(ret->ssl, ret->fd) == 0) { /* SSL_set_fd failed, log error */ error(errno, "SSL: OpenSSL: %.256s", ERR_error_string(ERR_get_error(), NULL)); return -1; } /* * make sure the socket is non-blocking while we do SSL_connect */ if (socket_set_blocking(ret->fd, 0) < 0) { return -1; } BIO_set_nbio(SSL_get_rbio(ret->ssl), 1); BIO_set_nbio(SSL_get_wbio(ret->ssl), 1); SSL_set_connect_state(ret->ssl); return 0; }
IoSecureSocket *IoSecureServer_tlsWrap(IoSecureServer *self, IoObject *locals, IoMessage *msg) { SSL_CTX *ctx = OCTX(self); IoSocket *sock = IoMessage_locals_socketArgAt_(msg, locals, 0); IoNumber *port = IoObject_getSlot_(sock, IOSYMBOL("port")); SSL *ssl = SSL_new(ctx); SSL_set_fd(ssl, IoSocket_rawDescriptor(sock)); set_nonblocking(SSL_get_rbio(ssl)); set_nonblocking(SSL_get_wbio(ssl)); SSL_set_accept_state(ssl); SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); IoIPAddress *ioaddr = IoIPAddress_new(IoObject_state(self)); IPAddress *iaddr = IoIPAddress_rawIPAddress(ioaddr); IPAddress_setIp_(iaddr, "0.0.0.0"); IPAddress_setPort_(iaddr, IoNumber_asLong(port)); IoSecureSocket *ssock = IoSecureSocket_newWithSSL_IP_(IoObject_state(self), ssl, ioaddr); return ssock; }
static int _checkSslRead(SSL* ssl, char* buffer, int len) { int ret = DTLS_FAIL; switch (SSL_get_error(ssl, len)) { case SSL_ERROR_NONE: // dprint("read %d bytes", (int) len); ret = DTLS_OK; break; case SSL_ERROR_ZERO_RETURN: // dprint("no data to read"); ret = DTLS_END; break; case SSL_ERROR_WANT_READ: /* Stop reading on socket timeout, otherwise try again */ if (BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL)) { derror("Timeout! No response received."); } break; case SSL_ERROR_SYSCALL: derror("Socket read error: "); _showSocketError(); break; case SSL_ERROR_SSL: derror("SSL read error: "); derror("%s (%d)", ERR_error_string(ERR_get_error(), buffer), SSL_get_error(ssl, len)); break; default: derror("Unexpected error while reading!\n"); break; } return ret; }
unsigned int psk_client_cb(SSL * ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) { BIO *b = SSL_get_rbio(ssl); struct conn *conn = b->ptr; // printf("KEYY: %s\n",conn->dtls_psk); snprintf(identity, max_identity_len, "CLient_identity"); int l = conn->dtls_psk_len < max_psk_len ? conn->dtls_psk_len : max_psk_len; memcpy(psk, conn->dtls_psk, l); return l; }
static SSL_SESSION *on_async_resumption_get(SSL *ssl, #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER) const #endif unsigned char *data, int len, int *copy) { h2o_socket_t *sock = BIO_get_data(SSL_get_rbio(ssl)); switch (sock->ssl->handshake.server.async_resumption.state) { case ASYNC_RESUMPTION_STATE_RECORD: sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_REQUEST_SENT; resumption_get_async(sock, h2o_iovec_init(data, len)); return NULL; case ASYNC_RESUMPTION_STATE_COMPLETE: *copy = 1; return sock->ssl->handshake.server.async_resumption.session_data; default: assert(!"FIXME"); return NULL; } }
void check_peers() { typedef struct bio_dgram_data_st { union { struct sockaddr sa; struct sockaddr_in sa_in; struct sockaddr_in6 sa_in6; } peer; unsigned int connected; unsigned int _errno; unsigned int mtu; struct timeval next_timeout; struct timeval socket_timeout; } bio_dgram_data; struct sockaddr_in6 peer; int i; BIO *bio; for (i = 0; i < MAX_SSL_PEERS; i++) { if (ssl_peer_storage[i]) { if (!ssl_peer_storage[i]->ssl) fprintf(stderr, "invalid SSL object for peer %d!\n",i); else { bio = SSL_get_rbio(ssl_peer_storage[i]->ssl); if (bio) { (void) BIO_dgram_get_peer(bio, (struct sockaddr *)&peer); if (peer.sin6_port && ssl_peer_storage[i]->h != ntohs(peer.sin6_port)) { fprintf(stderr, " bio %p: port differs from hash: %d != %d! (%sconnected)\n", bio, ssl_peer_storage[i]->h, ntohs(((struct sockaddr_in6 *)&peer)->sin6_port), ((bio_dgram_data *)bio->ptr)->connected ? "" : "not "); } } } } } }
int dtls1_read_failed(SSL *s, int code) { if ( code > 0) { fprintf( stderr, "invalid state reached %s:%d", __FILE__, __LINE__); return 1; } if (!dtls1_is_timer_expired(s)) { /* not a timeout, none of our business, let higher layers handle this. in fact it's probably an error */ return code; } if ( ! SSL_in_init(s)) /* done, no need to send a retransmit */ { BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ); return code; } #if 0 /* for now, each alert contains only one record number */ item = pqueue_peek(state->rcvd_records); if ( item ) { /* send an alert immediately for all the missing records */ } else #endif #if 0 /* no more alert sending, just retransmit the last set of messages */ if ( state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT) ssl3_send_alert(s,SSL3_AL_WARNING, DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); #endif return dtls1_handle_timeout(s); }
void dtls1_start_timer(SSL *s) { #ifndef OPENSSL_NO_SCTP /* Disable timer for SCTP */ if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { memset(&s->d1->next_timeout, 0, sizeof(s->d1->next_timeout)); return; } #endif /* If timer is not set, initialize duration with 1 second */ if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) { s->d1->timeout_duration = 1; } /* Set timeout to current time */ get_current_time(&(s->d1->next_timeout)); /* Add duration to current time */ s->d1->next_timeout.tv_sec += s->d1->timeout_duration; BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout)); }
int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int cookie_len) { unsigned char *buffer, result[EVP_MAX_MD_SIZE]; unsigned int length, resultlength; struct sockaddr_in peer; /* If secret isn't initialized yet, the cookie can't be valid */ if (!cookie_initialized) return 0; /* Read peer information */ (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); /* Create buffer with peer's address and port */ length = sizeof(peer.sin_addr); length += sizeof(peer.sin_port); buffer = (unsigned char*) OPENSSL_malloc(length); if (buffer == NULL) { BIO_printf(bio_err,"out of memory\n"); return 0; } memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr)); memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port)); /* Calculate HMAC of buffer using the secret */ HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, buffer, length, result, &resultlength); OPENSSL_free(buffer); if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0) return 1; return 0; }
static void print_stuff(BIO *bio, SSL *s, int full) { X509 *peer=NULL; char *p; static const char *space=" "; char buf[BUFSIZ]; STACK_OF(X509) *sk; STACK_OF(X509_NAME) *sk2; SSL_CIPHER *c; X509_NAME *xn; int j,i; #ifndef OPENSSL_NO_COMP const COMP_METHOD *comp, *expansion; #endif if (full) { int got_a_chain = 0; sk=SSL_get_peer_cert_chain(s); if (sk != NULL) { got_a_chain = 1; /* we don't have it for SSL2 (yet) */ BIO_printf(bio,"---\nCertificate chain\n"); for (i=0; i<sk_X509_num(sk); i++) { X509_NAME_oneline(X509_get_subject_name( sk_X509_value(sk,i)),buf,sizeof buf); BIO_printf(bio,"%2d s:%s\n",i,buf); X509_NAME_oneline(X509_get_issuer_name( sk_X509_value(sk,i)),buf,sizeof buf); BIO_printf(bio," i:%s\n",buf); if (c_showcerts) PEM_write_bio_X509(bio,sk_X509_value(sk,i)); } } BIO_printf(bio,"---\n"); peer=SSL_get_peer_certificate(s); if (peer != NULL) { BIO_printf(bio,"Server certificate\n"); if (!(c_showcerts && got_a_chain)) /* Redundant if we showed the whole chain */ PEM_write_bio_X509(bio,peer); X509_NAME_oneline(X509_get_subject_name(peer), buf,sizeof buf); BIO_printf(bio,"subject=%s\n",buf); X509_NAME_oneline(X509_get_issuer_name(peer), buf,sizeof buf); BIO_printf(bio,"issuer=%s\n",buf); } else BIO_printf(bio,"no peer certificate available\n"); sk2=SSL_get_client_CA_list(s); if ((sk2 != NULL) && (sk_X509_NAME_num(sk2) > 0)) { BIO_printf(bio,"---\nAcceptable client certificate CA names\n"); for (i=0; i<sk_X509_NAME_num(sk2); i++) { xn=sk_X509_NAME_value(sk2,i); X509_NAME_oneline(xn,buf,sizeof(buf)); BIO_write(bio,buf,strlen(buf)); BIO_write(bio,"\n",1); } } else { BIO_printf(bio,"---\nNo client certificate CA names sent\n"); } p=SSL_get_shared_ciphers(s,buf,sizeof buf); if (p != NULL) { /* This works only for SSL 2. In later protocol * versions, the client does not know what other * ciphers (in addition to the one to be used * in the current connection) the server supports. */ BIO_printf(bio,"---\nCiphers common between both SSL endpoints:\n"); j=i=0; while (*p) { if (*p == ':') { BIO_write(bio,space,15-j%25); i++; j=0; BIO_write(bio,((i%3)?" ":"\n"),1); } else { BIO_write(bio,p,1); j++; } p++; } BIO_write(bio,"\n",1); } BIO_printf(bio,"---\nSSL handshake has read %ld bytes and written %ld bytes\n", BIO_number_read(SSL_get_rbio(s)), BIO_number_written(SSL_get_wbio(s))); } BIO_printf(bio,((s->hit)?"---\nReused, ":"---\nNew, ")); c=SSL_get_current_cipher(s); BIO_printf(bio,"%s, Cipher is %s\n", SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c)); if (peer != NULL) { EVP_PKEY *pktmp; pktmp = X509_get_pubkey(peer); BIO_printf(bio,"Server public key is %d bit\n", EVP_PKEY_bits(pktmp)); EVP_PKEY_free(pktmp); } #ifndef OPENSSL_NO_COMP comp=SSL_get_current_compression(s); expansion=SSL_get_current_expansion(s); BIO_printf(bio,"Compression: %s\n", comp ? SSL_COMP_get_name(comp) : "NONE"); BIO_printf(bio,"Expansion: %s\n", expansion ? SSL_COMP_get_name(expansion) : "NONE"); #endif SSL_SESSION_print(bio,SSL_get_session(s)); BIO_printf(bio,"---\n"); if (peer != NULL) X509_free(peer); /* flush, or debugging output gets mixed with http response */ (void)BIO_flush(bio); }
int dtls1_accept(SSL *s) { BUF_MEM *buf; unsigned long Time=(unsigned long)time(NULL); void (*cb)(const SSL *ssl,int type,int val)=NULL; unsigned long alg_k; int ret= -1; int new_state,state,skip=0; int listen; #ifndef OPENSSL_NO_SCTP unsigned char sctpauthkey[64]; char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; #endif RAND_add(&Time,sizeof(Time),0); ERR_clear_error(); clear_sys_error(); if (s->info_callback != NULL) cb=s->info_callback; else if (s->ctx->info_callback != NULL) cb=s->ctx->info_callback; listen = s->d1->listen; /* init things to blank */ s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); s->d1->listen = listen; #ifndef OPENSSL_NO_SCTP /* Notify SCTP BIO socket to enter handshake * mode and prevent stream identifier other * than 0. Will be ignored if no SCTP is used. */ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL); #endif if (s->cert == NULL) { SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_NO_CERTIFICATE_SET); return(-1); } #ifndef OPENSSL_NO_HEARTBEATS /* If we're awaiting a HeartbeatResponse, pretend we * already got and don't await it anymore, because * Heartbeats don't make sense during handshakes anyway. */ if (s->tlsext_hb_pending) { dtls1_stop_timer(s); s->tlsext_hb_pending = 0; s->tlsext_hb_seq++; } #endif for (;;) { state=s->state; switch (s->state) { case SSL_ST_RENEGOTIATE: s->renegotiate=1; /* s->state=SSL_ST_ACCEPT; */ case SSL_ST_BEFORE: case SSL_ST_ACCEPT: case SSL_ST_BEFORE|SSL_ST_ACCEPT: case SSL_ST_OK|SSL_ST_ACCEPT: s->server=1; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) { SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR); return -1; } s->type=SSL_ST_ACCEPT; if (s->init_buf == NULL) { if ((buf=BUF_MEM_new()) == NULL) { ret= -1; goto end; } if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH)) { ret= -1; goto end; } s->init_buf=buf; } if (!ssl3_setup_buffers(s)) { ret= -1; goto end; } s->init_num=0; if (s->state != SSL_ST_RENEGOTIATE) { /* Ok, we now need to push on a buffering BIO so that * the output is sent in a way that TCP likes :-) * ...but not with SCTP :-) */ #ifndef OPENSSL_NO_SCTP if (!BIO_dgram_is_sctp(SSL_get_wbio(s))) #endif if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; } ssl3_init_finished_mac(s); s->state=SSL3_ST_SR_CLNT_HELLO_A; s->ctx->stats.sess_accept++; } else { /* s->state == SSL_ST_RENEGOTIATE, * we will just send a HelloRequest */ s->ctx->stats.sess_accept_renegotiate++; s->state=SSL3_ST_SW_HELLO_REQ_A; } break; case SSL3_ST_SW_HELLO_REQ_A: case SSL3_ST_SW_HELLO_REQ_B: s->shutdown=0; dtls1_clear_record_buffer(s); dtls1_start_timer(s); ret=ssl3_send_hello_request(s); if (ret <= 0) goto end; s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A; s->state=SSL3_ST_SW_FLUSH; s->init_num=0; ssl3_init_finished_mac(s); break; case SSL3_ST_SW_HELLO_REQ_C: s->state=SSL_ST_OK; break; case SSL3_ST_SR_CLNT_HELLO_A: case SSL3_ST_SR_CLNT_HELLO_B: case SSL3_ST_SR_CLNT_HELLO_C: s->shutdown=0; ret=ssl3_get_client_hello(s); if (ret <= 0) goto end; dtls1_stop_timer(s); if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A; else s->state = SSL3_ST_SW_SRVR_HELLO_A; s->init_num=0; /* Reflect ClientHello sequence to remain stateless while listening */ if (listen) { memcpy(s->s3->write_sequence, s->s3->read_sequence, sizeof(s->s3->write_sequence)); } /* If we're just listening, stop here */ if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A) { ret = 2; s->d1->listen = 0; /* Set expected sequence numbers * to continue the handshake. */ s->d1->handshake_read_seq = 2; s->d1->handshake_write_seq = 1; s->d1->next_handshake_write_seq = 1; goto end; } break; case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: ret = dtls1_send_hello_verify_request(s); if ( ret <= 0) goto end; s->state=SSL3_ST_SW_FLUSH; s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A; /* HelloVerifyRequest resets Finished MAC */ if (s->version != DTLS1_BAD_VER) ssl3_init_finished_mac(s); break; #ifndef OPENSSL_NO_SCTP case DTLS1_SCTP_ST_SR_READ_SOCK: if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) { s->s3->in_read_app_data=2; s->rwstate=SSL_READING; BIO_clear_retry_flags(SSL_get_rbio(s)); BIO_set_retry_read(SSL_get_rbio(s)); ret = -1; goto end; } s->state=SSL3_ST_SR_FINISHED_A; break; case DTLS1_SCTP_ST_SW_WRITE_SOCK: ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s)); if (ret < 0) goto end; if (ret == 0) { if (s->d1->next_state != SSL_ST_OK) { s->s3->in_read_app_data=2; s->rwstate=SSL_READING; BIO_clear_retry_flags(SSL_get_rbio(s)); BIO_set_retry_read(SSL_get_rbio(s)); ret = -1; goto end; } } s->state=s->d1->next_state; break; #endif case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_B: s->renegotiate = 2; dtls1_start_timer(s); ret=ssl3_send_server_hello(s); if (ret <= 0) goto end; if (s->hit) { #ifndef OPENSSL_NO_SCTP /* Add new shared key for SCTP-Auth, * will be ignored if no SCTP used. */ snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), DTLS1_SCTP_AUTH_LABEL); SSL_export_keying_material(s, sctpauthkey, sizeof(sctpauthkey), labelbuffer, sizeof(labelbuffer), NULL, 0, 0); BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, sizeof(sctpauthkey), sctpauthkey); #endif #ifndef OPENSSL_NO_TLSEXT if (s->tlsext_ticket_expected) s->state=SSL3_ST_SW_SESSION_TICKET_A; else s->state=SSL3_ST_SW_CHANGE_A; #else s->state=SSL3_ST_SW_CHANGE_A; #endif } else s->state=SSL3_ST_SW_CERT_A; s->init_num=0; break; case SSL3_ST_SW_CERT_A: case SSL3_ST_SW_CERT_B: /* Check if it is anon DH or normal PSK */ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { dtls1_start_timer(s); ret=ssl3_send_server_certificate(s); if (ret <= 0) goto end; #ifndef OPENSSL_NO_TLSEXT if (s->tlsext_status_expected) s->state=SSL3_ST_SW_CERT_STATUS_A; else s->state=SSL3_ST_SW_KEY_EXCH_A; } else { skip = 1; s->state=SSL3_ST_SW_KEY_EXCH_A; } #else } else skip=1; s->state=SSL3_ST_SW_KEY_EXCH_A; #endif s->init_num=0; break; case SSL3_ST_SW_KEY_EXCH_A: case SSL3_ST_SW_KEY_EXCH_B: alg_k = s->s3->tmp.new_cipher->algorithm_mkey; /* clear this, it may get reset by * send_server_key_exchange */ if ((s->options & SSL_OP_EPHEMERAL_RSA) #ifndef OPENSSL_NO_KRB5 && !(alg_k & SSL_kKRB5) #endif /* OPENSSL_NO_KRB5 */ ) /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key * even when forbidden by protocol specs * (handshake may fail as clients are not required to * be able to handle this) */ s->s3->tmp.use_rsa_tmp=1; else s->s3->tmp.use_rsa_tmp=0; /* only send if a DH key exchange or * RSA but we have a sign only certificate */ if (s->s3->tmp.use_rsa_tmp /* PSK: send ServerKeyExchange if PSK identity * hint if provided */ #ifndef OPENSSL_NO_PSK || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) #endif || (alg_k & (SSL_kDHE|SSL_kDHr|SSL_kDHd)) || (alg_k & SSL_kECDHE) || ((alg_k & SSL_kRSA) && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher) ) ) ) ) { dtls1_start_timer(s); ret=ssl3_send_server_key_exchange(s); if (ret <= 0) goto end; } else skip=1; s->state=SSL3_ST_SW_CERT_REQ_A; s->init_num=0; break; case SSL3_ST_SW_CERT_REQ_A: case SSL3_ST_SW_CERT_REQ_B: if (/* don't request cert unless asked for it: */ !(s->verify_mode & SSL_VERIFY_PEER) || /* if SSL_VERIFY_CLIENT_ONCE is set, * don't request cert during re-negotiation: */ ((s->session->peer != NULL) && (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || /* never request cert in anonymous ciphersuites * (see section "Certificate request" in SSL 3 drafts * and in RFC 2246): */ ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && /* ... except when the application insists on verification * (against the specs, but s3_clnt.c accepts this for SSL 3) */ !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) || /* never request cert in Kerberos ciphersuites */ (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) /* With normal PSK Certificates and * Certificate Requests are omitted */ || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { /* no cert request */ skip=1; s->s3->tmp.cert_request=0; s->state=SSL3_ST_SW_SRVR_DONE_A; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A; s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK; } #endif } else { s->s3->tmp.cert_request=1; dtls1_start_timer(s); ret=ssl3_send_certificate_request(s); if (ret <= 0) goto end; #ifndef NETSCAPE_HANG_BUG s->state=SSL3_ST_SW_SRVR_DONE_A; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A; s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK; } #endif #else s->state=SSL3_ST_SW_FLUSH; s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { s->d1->next_state = s->s3->tmp.next_state; s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK; } #endif #endif s->init_num=0; } break; case SSL3_ST_SW_SRVR_DONE_A: case SSL3_ST_SW_SRVR_DONE_B: dtls1_start_timer(s); ret=ssl3_send_server_done(s); if (ret <= 0) goto end; s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; s->state=SSL3_ST_SW_FLUSH; s->init_num=0; break; case SSL3_ST_SW_FLUSH: s->rwstate=SSL_WRITING; if (BIO_flush(s->wbio) <= 0) { /* If the write error was fatal, stop trying */ if (!BIO_should_retry(s->wbio)) { s->rwstate=SSL_NOTHING; s->state=s->s3->tmp.next_state; } ret= -1; goto end; } s->rwstate=SSL_NOTHING; s->state=s->s3->tmp.next_state; break; case SSL3_ST_SR_CERT_A: case SSL3_ST_SR_CERT_B: /* Check for second client hello (MS SGC) */ ret = ssl3_check_client_hello(s); if (ret <= 0) goto end; if (ret == 2) { dtls1_stop_timer(s); s->state = SSL3_ST_SR_CLNT_HELLO_C; } else { /* could be sent for a DH cert, even if we * have not asked for it :-) */ ret=ssl3_get_client_certificate(s); if (ret <= 0) goto end; s->init_num=0; s->state=SSL3_ST_SR_KEY_EXCH_A; } break; case SSL3_ST_SR_KEY_EXCH_A: case SSL3_ST_SR_KEY_EXCH_B: ret=ssl3_get_client_key_exchange(s); if (ret <= 0) goto end; #ifndef OPENSSL_NO_SCTP /* Add new shared key for SCTP-Auth, * will be ignored if no SCTP used. */ snprintf((char *) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), DTLS1_SCTP_AUTH_LABEL); SSL_export_keying_material(s, sctpauthkey, sizeof(sctpauthkey), labelbuffer, sizeof(labelbuffer), NULL, 0, 0); BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, sizeof(sctpauthkey), sctpauthkey); #endif s->state=SSL3_ST_SR_CERT_VRFY_A; s->init_num=0; if (ret == 2) { /* For the ECDH ciphersuites when * the client sends its ECDH pub key in * a certificate, the CertificateVerify * message is not sent. */ s->state=SSL3_ST_SR_FINISHED_A; s->init_num = 0; } else if (SSL_USE_SIGALGS(s)) { s->state=SSL3_ST_SR_CERT_VRFY_A; s->init_num=0; if (!s->session->peer) break; /* For sigalgs freeze the handshake buffer * at this point and digest cached records. */ if (!s->s3->handshake_buffer) { SSLerr(SSL_F_DTLS1_ACCEPT,ERR_R_INTERNAL_ERROR); return -1; } s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE; if (!ssl3_digest_cached_records(s)) return -1; } else { s->state=SSL3_ST_SR_CERT_VRFY_A; s->init_num=0; /* We need to get hashes here so if there is * a client cert, it can be verified */ s->method->ssl3_enc->cert_verify_mac(s, NID_md5, &(s->s3->tmp.cert_verify_md[0])); s->method->ssl3_enc->cert_verify_mac(s, NID_sha1, &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH])); } break; case SSL3_ST_SR_CERT_VRFY_A: case SSL3_ST_SR_CERT_VRFY_B: s->d1->change_cipher_spec_ok = 1; /* we should decide if we expected this one */ ret=ssl3_get_cert_verify(s); if (ret <= 0) goto end; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && state == SSL_ST_RENEGOTIATE) s->state=DTLS1_SCTP_ST_SR_READ_SOCK; else #endif s->state=SSL3_ST_SR_FINISHED_A; s->init_num=0; break; case SSL3_ST_SR_FINISHED_A: case SSL3_ST_SR_FINISHED_B: s->d1->change_cipher_spec_ok = 1; ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A, SSL3_ST_SR_FINISHED_B); if (ret <= 0) goto end; dtls1_stop_timer(s); if (s->hit) s->state=SSL_ST_OK; #ifndef OPENSSL_NO_TLSEXT else if (s->tlsext_ticket_expected) s->state=SSL3_ST_SW_SESSION_TICKET_A; #endif else s->state=SSL3_ST_SW_CHANGE_A; s->init_num=0; break; #ifndef OPENSSL_NO_TLSEXT case SSL3_ST_SW_SESSION_TICKET_A: case SSL3_ST_SW_SESSION_TICKET_B: ret=ssl3_send_newsession_ticket(s); if (ret <= 0) goto end; s->state=SSL3_ST_SW_CHANGE_A; s->init_num=0; break; case SSL3_ST_SW_CERT_STATUS_A: case SSL3_ST_SW_CERT_STATUS_B: ret=ssl3_send_cert_status(s); if (ret <= 0) goto end; s->state=SSL3_ST_SW_KEY_EXCH_A; s->init_num=0; break; #endif case SSL3_ST_SW_CHANGE_A: case SSL3_ST_SW_CHANGE_B: s->session->cipher=s->s3->tmp.new_cipher; if (!s->method->ssl3_enc->setup_key_block(s)) { ret= -1; goto end; } ret=dtls1_send_change_cipher_spec(s, SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B); if (ret <= 0) goto end; #ifndef OPENSSL_NO_SCTP if (!s->hit) { /* Change to new shared key of SCTP-Auth, * will be ignored if no SCTP used. */ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL); } #endif s->state=SSL3_ST_SW_FINISHED_A; s->init_num=0; if (!s->method->ssl3_enc->change_cipher_state(s, SSL3_CHANGE_CIPHER_SERVER_WRITE)) { ret= -1; goto end; } dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); break; case SSL3_ST_SW_FINISHED_A: case SSL3_ST_SW_FINISHED_B: ret=ssl3_send_finished(s, SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B, s->method->ssl3_enc->server_finished_label, s->method->ssl3_enc->server_finished_label_len); if (ret <= 0) goto end; s->state=SSL3_ST_SW_FLUSH; if (s->hit) { s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A; #ifndef OPENSSL_NO_SCTP /* Change to new shared key of SCTP-Auth, * will be ignored if no SCTP used. */ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL); #endif } else { s->s3->tmp.next_state=SSL_ST_OK; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { s->d1->next_state = s->s3->tmp.next_state; s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK; } #endif } s->init_num=0; break; case SSL_ST_OK: /* clean a few things up */ ssl3_cleanup_key_block(s); #if 0 BUF_MEM_free(s->init_buf); s->init_buf=NULL; #endif /* remove buffering on output */ ssl_free_wbio_buffer(s); s->init_num=0; if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */ { s->renegotiate=0; s->new_session=0; ssl_update_cache(s,SSL_SESS_CACHE_SERVER); s->ctx->stats.sess_accept_good++; /* s->server=1; */ s->handshake_func=dtls1_accept; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1); } ret = 1; /* done handshaking, next message is client hello */ s->d1->handshake_read_seq = 0; /* next message is server hello */ s->d1->handshake_write_seq = 0; s->d1->next_handshake_write_seq = 0; goto end; /* break; */ default: SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_UNKNOWN_STATE); ret= -1; goto end; /* break; */ }
static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) { BIO* ssl_rbio; BIO* ssl_wbio; BIO* next_bio; int status = -1; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) BIO_get_data(bio); if (!tls) return 0; if (!tls->ssl && (cmd != BIO_C_SET_SSL)) return 0; next_bio = BIO_next(bio); ssl_rbio = tls->ssl ? SSL_get_rbio(tls->ssl) : NULL; ssl_wbio = tls->ssl ? SSL_get_wbio(tls->ssl) : NULL; switch (cmd) { case BIO_CTRL_RESET: SSL_shutdown(tls->ssl); if (SSL_in_connect_init(tls->ssl)) SSL_set_connect_state(tls->ssl); else if (SSL_in_accept_init(tls->ssl)) SSL_set_accept_state(tls->ssl); SSL_clear(tls->ssl); if (next_bio) status = BIO_ctrl(next_bio, cmd, num, ptr); else if (ssl_rbio) status = BIO_ctrl(ssl_rbio, cmd, num, ptr); else status = 1; break; case BIO_C_GET_FD: status = BIO_ctrl(ssl_rbio, cmd, num, ptr); break; case BIO_CTRL_INFO: status = 0; break; case BIO_CTRL_SET_CALLBACK: status = 0; break; case BIO_CTRL_GET_CALLBACK: *((ULONG_PTR*) ptr) = (ULONG_PTR) SSL_get_info_callback(tls->ssl); status = 1; break; case BIO_C_SSL_MODE: if (num) SSL_set_connect_state(tls->ssl); else SSL_set_accept_state(tls->ssl); status = 1; break; case BIO_CTRL_GET_CLOSE: status = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(bio, (int) num); status = 1; break; case BIO_CTRL_WPENDING: status = BIO_ctrl(ssl_wbio, cmd, num, ptr); break; case BIO_CTRL_PENDING: status = SSL_pending(tls->ssl); if (status == 0) status = BIO_pending(ssl_rbio); break; case BIO_CTRL_FLUSH: BIO_clear_retry_flags(bio); status = BIO_ctrl(ssl_wbio, cmd, num, ptr); BIO_copy_next_retry(bio); status = 1; break; case BIO_CTRL_PUSH: if (next_bio && (next_bio != ssl_rbio)) { #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_set_bio(tls->ssl, next_bio, next_bio); CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO); #else /* * We are going to pass ownership of next to the SSL object...but * we don't own a reference to pass yet - so up ref */ BIO_up_ref(next_bio); SSL_set_bio(tls->ssl, next_bio, next_bio); #endif } status = 1; break; case BIO_CTRL_POP: /* Only detach if we are the BIO explicitly being popped */ if (bio == ptr) { if (ssl_rbio != ssl_wbio) BIO_free_all(ssl_wbio); #if OPENSSL_VERSION_NUMBER < 0x10100000L if (next_bio) CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO); tls->ssl->wbio = tls->ssl->rbio = NULL; #else /* OpenSSL 1.1: This will also clear the reference we obtained during push */ SSL_set_bio(tls->ssl, NULL, NULL); #endif } status = 1; break; case BIO_C_GET_SSL: if (ptr) { *((SSL**) ptr) = tls->ssl; status = 1; } break; case BIO_C_SET_SSL: BIO_set_shutdown(bio, (int) num); if (ptr) { tls->ssl = (SSL*) ptr; ssl_rbio = SSL_get_rbio(tls->ssl); ssl_wbio = SSL_get_wbio(tls->ssl); } if (ssl_rbio) { if (next_bio) BIO_push(ssl_rbio, next_bio); BIO_set_next(bio, ssl_rbio); #if OPENSSL_VERSION_NUMBER < 0x10100000L CRYPTO_add(&(ssl_rbio->references), 1, CRYPTO_LOCK_BIO); #else BIO_up_ref(ssl_rbio); #endif } BIO_set_init(bio, 1); status = 1; break; case BIO_C_DO_STATE_MACHINE: BIO_clear_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL); BIO_set_retry_reason(bio, 0); status = SSL_do_handshake(tls->ssl); if (status <= 0) { switch (SSL_get_error(tls->ssl, status)) { case SSL_ERROR_WANT_READ: BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_WRITE: BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY); BIO_set_retry_reason(bio, BIO_get_retry_reason(next_bio)); break; default: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; } } break; default: status = BIO_ctrl(ssl_rbio, cmd, num, ptr); break; } return status; }
/* * This is the actual startup routine for the connection. We expect that the * buffers are flushed and the "220 Ready to start TLS" was received by us, * so that we can immediately start the TLS handshake process. */ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) { int sts; int protomask; const char *cipher_list; SSL_SESSION *session = 0; SSL_CIPHER_const SSL_CIPHER *cipher; X509 *peercert; TLS_SESS_STATE *TLScontext; TLS_APPL_STATE *app_ctx = props->ctx; char *myserverid; int log_mask = app_ctx->log_mask; /* * When certificate verification is required, log trust chain validation * errors even when disabled by default for opportunistic sessions. For * DANE this only applies when using trust-anchor associations. */ if (TLS_MUST_TRUST(props->tls_level) && (!TLS_DANE_BASED(props->tls_level) || TLS_DANE_HASTA(props->dane))) log_mask |= TLS_LOG_UNTRUSTED; if (log_mask & TLS_LOG_VERBOSE) msg_info("setting up TLS connection to %s", props->namaddr); /* * First make sure we have valid protocol and cipher parameters * * Per-session protocol restrictions must be applied to the SSL connection, * as restrictions in the global context cannot be cleared. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session", props->namaddr, props->protocols); return (0); } /* DANE requires SSLv3 or later, not SSLv2. */ if (TLS_DANE_BASED(props->tls_level)) protomask |= TLS_PROTOCOL_SSLv2; /* * Per session cipher selection for sessions with mandatory encryption * * The cipherlist is applied to the global SSL context, since it is likely * to stay the same between connections, so we make use of a 1-element * cache to return the same result for identical inputs. */ cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { msg_warn("%s: %s: aborting TLS session", props->namaddr, vstring_str(app_ctx->why)); return (0); } if (log_mask & TLS_LOG_VERBOSE) msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); /* * OpenSSL will ignore cached sessions that use the wrong protocol. So we * do not need to filter out cached sessions with the "wrong" protocol, * rather OpenSSL will simply negotiate a new session. * * We salt the session lookup key with the protocol list, so that sessions * found in the cache are plausibly acceptable. * * By the time a TLS client is negotiating ciphers it has already offered to * re-use a session, it is too late to renege on the offer. So we must * not attempt to re-use sessions whose ciphers are too weak. We salt the * session lookup key with the cipher list, so that sessions found in the * cache are always acceptable. * * With DANE, (more generally any TLScontext where we specified explicit * trust-anchor or end-entity certificates) the verification status of * the SSL session depends on the specified list. Since we verify the * certificate only during the initial handshake, we must segregate * sessions with different TA lists. Note, that TA re-verification is * not possible with cached sessions, since these don't hold the complete * peer trust chain. Therefore, we compute a digest of the sorted TA * parameters and append it to the serverid. */ myserverid = tls_serverid_digest(props, protomask, cipher_list); /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve * the information inside the tls_verify_certificate_callback(). * * If session caching was enabled when TLS was initialized, the cache type * is stored in the client SSL context. */ TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; TLScontext->serverid = myserverid; TLScontext->stream = props->stream; TLScontext->mdalg = props->mdalg; /* Alias DANE digest info from props */ TLScontext->dane = props->dane; if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); tls_print_errors(); tls_free_context(TLScontext); return (0); } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * Apply session protocol restrictions. */ if (protomask != 0) SSL_set_options(TLScontext->con, TLS_SSL_OP_PROTOMASK(protomask)); /* * XXX To avoid memory leaks we must always call SSL_SESSION_free() after * calling SSL_set_session(), regardless of whether or not the session * will be reused. */ if (TLScontext->cache_type) { session = load_clnt_session(TLScontext); if (session) { SSL_set_session(TLScontext->con, session); SSL_SESSION_free(session); /* 200411 */ } } #ifdef TLSEXT_MAXLEN_host_name if (TLS_DANE_BASED(props->tls_level) && strlen(props->host) <= TLSEXT_MAXLEN_host_name) { /* * With DANE sessions, send an SNI hint. We don't care whether the * server reports finding a matching certificate or not, so no * callback is required to process the server response. Our use of * SNI is limited to giving servers that are (mis)configured to use * SNI the best opportunity to find the certificate they promised via * the associated TLSA RRs. (Generally, server administrators should * avoid SNI, and there are no plans to support SNI in the Postfix * SMTP server). * * Since the hostname is DNSSEC-validated, it must be a DNS FQDN and * thererefore valid for use with SNI. Failure to set a valid SNI * hostname is a memory allocation error, and thus transient. Since * we must not cache the session if we failed to send the SNI name, * we have little choice but to abort. */ if (!SSL_set_tlsext_host_name(TLScontext->con, props->host)) { msg_warn("%s: error setting SNI hostname to: %s", props->namaddr, props->host); tls_free_context(TLScontext); return (0); } if (log_mask & TLS_LOG_DEBUG) msg_info("%s: SNI hostname: %s", props->namaddr, props->host); } #endif /* * Before really starting anything, try to seed the PRNG a little bit * more. */ tls_int_seed(); (void) tls_ext_seed(var_tls_daemon_rand_bytes); /* * Initialize the SSL connection to connect state. This should not be * necessary anymore since 0.9.3, but the call is still in the library * and maintaining compatibility never hurts. */ SSL_set_connect_state(TLScontext->con); /* * Connect the SSL connection with the network socket. */ if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) { msg_info("SSL_set_fd error to %s", props->namaddr); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* * Turn on non-blocking I/O so that we can enforce timeouts on network * I/O. */ non_blocking(vstream_fileno(props->stream), NON_BLOCKING); /* * If the debug level selected is high enough, all of the data is dumped: * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will * dump everything. * * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? * Well there is a BIO below the SSL routines that is automatically * created for us, so we can use it for debugging purposes. */ if (log_mask & TLS_LOG_TLSPKTS) BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext); /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for certificate verification. * * Error handling: If the SSL handhake fails, we print out an error message * and remove all TLS state concerning this session. */ sts = tls_bio_connect(vstream_fileno(props->stream), props->timeout, TLScontext); if (sts <= 0) { if (ERR_peek_error() != 0) { msg_info("SSL_connect error to %s: %d", props->namaddr, sts); tls_print_errors(); } else if (errno != 0) { msg_info("SSL_connect error to %s: %m", props->namaddr); } else { msg_info("SSL_connect error to %s: lost connection", props->namaddr); } uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* Turn off packet dump if only dumping the handshake */ if ((log_mask & TLS_LOG_ALLPKTS) == 0) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* * The caller may want to know if this session was reused or if a new * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) msg_info("%s: Reusing old session", TLScontext->namaddr); /* * Do peername verification if requested and extract useful information * from the certificate for later use. */ if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) { TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; /* * Peer name or fingerprint verification as requested. * Unconditionally set peer_CN, issuer_CN and peer_cert_fprint. Check * fingerprint first, and avoid logging verified as untrusted in the * call to verify_extract_name(). */ verify_extract_print(TLScontext, peercert, props); verify_extract_name(TLScontext, peercert, props); if (TLScontext->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT)) msg_info("%s: subject_CN=%s, issuer_CN=%s, " "fingerprint=%s, pkey_fingerprint=%s", props->namaddr, TLScontext->peer_CN, TLScontext->issuer_CN, TLScontext->peer_cert_fprint, TLScontext->peer_pkey_fprint); X509_free(peercert); } else { TLScontext->issuer_CN = mystrdup(""); TLScontext->peer_CN = mystrdup(""); TLScontext->peer_cert_fprint = mystrdup(""); TLScontext->peer_pkey_fprint = mystrdup(""); } /* * Finally, collect information about protocol and cipher for logging */ TLScontext->protocol = SSL_get_version(TLScontext->con); cipher = SSL_get_current_cipher(TLScontext->con); TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, &(TLScontext->cipher_algbits)); /* * The TLS engine is active. Switch to the tls_timed_read/write() * functions and make the TLScontext available to those functions. */ tls_stream_start(props->stream, TLScontext); /* * All the key facts in a single log entry. */ if (log_mask & TLS_LOG_SUMMARY) msg_info("%s TLS connection established to %s: %s with cipher %s " "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" : TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", props->namaddr, TLScontext->protocol, TLScontext->cipher_name, TLScontext->cipher_usebits, TLScontext->cipher_algbits); tls_int_seed(); return (TLScontext); }
int dtls1_connect(SSL *s) { BUF_MEM *buf=NULL; unsigned long Time=(unsigned long)time(NULL); void (*cb)(const SSL *ssl,int type,int val)=NULL; int ret= -1; int new_state,state,skip=0; #ifndef OPENSSL_NO_SCTP unsigned char sctpauthkey[64]; char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; #endif RAND_add(&Time,sizeof(Time),0); ERR_clear_error(); clear_sys_error(); if (s->info_callback != NULL) cb=s->info_callback; else if (s->ctx->info_callback != NULL) cb=s->ctx->info_callback; s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); #ifndef OPENSSL_NO_SCTP /* Notify SCTP BIO socket to enter handshake * mode and prevent stream identifier other * than 0. Will be ignored if no SCTP is used. */ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL); #endif #ifndef OPENSSL_NO_HEARTBEATS /* If we're awaiting a HeartbeatResponse, pretend we * already got and don't await it anymore, because * Heartbeats don't make sense during handshakes anyway. */ if (s->tlsext_hb_pending) { dtls1_stop_timer(s); s->tlsext_hb_pending = 0; s->tlsext_hb_seq++; } #endif for (;;) { state=s->state; switch(s->state) { case SSL_ST_RENEGOTIATE: s->renegotiate=1; s->state=SSL_ST_CONNECT; s->ctx->stats.sess_connect_renegotiate++; /* break */ case SSL_ST_BEFORE: case SSL_ST_CONNECT: case SSL_ST_BEFORE|SSL_ST_CONNECT: case SSL_ST_OK|SSL_ST_CONNECT: s->server=0; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00) && (s->version & 0xff00 ) != (DTLS1_BAD_VER & 0xff00)) { SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR); ret = -1; goto end; } /* s->version=SSL3_VERSION; */ s->type=SSL_ST_CONNECT; if (s->init_buf == NULL) { if ((buf=BUF_MEM_new()) == NULL) { ret= -1; goto end; } if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH)) { ret= -1; goto end; } s->init_buf=buf; buf=NULL; } if (!ssl3_setup_buffers(s)) { ret= -1; goto end; } /* setup buffing BIO */ if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; } /* don't push the buffering BIO quite yet */ s->state=SSL3_ST_CW_CLNT_HELLO_A; s->ctx->stats.sess_connect++; s->init_num=0; /* mark client_random uninitialized */ memset(s->s3->client_random,0,sizeof(s->s3->client_random)); s->d1->send_cookie = 0; s->hit = 0; break; #ifndef OPENSSL_NO_SCTP case DTLS1_SCTP_ST_CR_READ_SOCK: if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) { s->s3->in_read_app_data=2; s->rwstate=SSL_READING; BIO_clear_retry_flags(SSL_get_rbio(s)); BIO_set_retry_read(SSL_get_rbio(s)); ret = -1; goto end; } s->state=s->s3->tmp.next_state; break; case DTLS1_SCTP_ST_CW_WRITE_SOCK: /* read app data until dry event */ ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s)); if (ret < 0) goto end; if (ret == 0) { s->s3->in_read_app_data=2; s->rwstate=SSL_READING; BIO_clear_retry_flags(SSL_get_rbio(s)); BIO_set_retry_read(SSL_get_rbio(s)); ret = -1; goto end; } s->state=s->d1->next_state; break; #endif case SSL3_ST_CW_CLNT_HELLO_A: case SSL3_ST_CW_CLNT_HELLO_B: s->shutdown=0; /* every DTLS ClientHello resets Finished MAC */ ssl3_init_finished_mac(s); dtls1_start_timer(s); ret=dtls1_client_hello(s); if (ret <= 0) goto end; if ( s->d1->send_cookie) { s->state=SSL3_ST_CW_FLUSH; s->s3->tmp.next_state=SSL3_ST_CR_SRVR_HELLO_A; } else s->state=SSL3_ST_CR_SRVR_HELLO_A; s->init_num=0; #ifndef OPENSSL_NO_SCTP /* Disable buffering for SCTP */ if (!BIO_dgram_is_sctp(SSL_get_wbio(s))) { #endif /* turn on buffering for the next lot of output */ if (s->bbio != s->wbio) s->wbio=BIO_push(s->bbio,s->wbio); #ifndef OPENSSL_NO_SCTP } #endif break; case SSL3_ST_CR_SRVR_HELLO_A: case SSL3_ST_CR_SRVR_HELLO_B: ret=ssl3_get_server_hello(s); if (ret <= 0) goto end; else { if (s->hit) { #ifndef OPENSSL_NO_SCTP /* Add new shared key for SCTP-Auth, * will be ignored if no SCTP used. */ snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), DTLS1_SCTP_AUTH_LABEL); SSL_export_keying_material(s, sctpauthkey, sizeof(sctpauthkey), labelbuffer, sizeof(labelbuffer), NULL, 0, 0); BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, sizeof(sctpauthkey), sctpauthkey); #endif s->state=SSL3_ST_CR_FINISHED_A; } else s->state=DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A; } s->init_num=0; break; case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: ret = dtls1_get_hello_verify(s); if ( ret <= 0) goto end; dtls1_stop_timer(s); if ( s->d1->send_cookie) /* start again, with a cookie */ s->state=SSL3_ST_CW_CLNT_HELLO_A; else s->state = SSL3_ST_CR_CERT_A; s->init_num = 0; break; case SSL3_ST_CR_CERT_A: case SSL3_ST_CR_CERT_B: #ifndef OPENSSL_NO_TLSEXT ret=ssl3_check_finished(s); if (ret <= 0) goto end; if (ret == 2) { s->hit = 1; if (s->tlsext_ticket_expected) s->state=SSL3_ST_CR_SESSION_TICKET_A; else s->state=SSL3_ST_CR_FINISHED_A; s->init_num=0; break; } #endif /* Check if it is anon DH or PSK */ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { ret=ssl3_get_server_certificate(s); if (ret <= 0) goto end; #ifndef OPENSSL_NO_TLSEXT if (s->tlsext_status_expected) s->state=SSL3_ST_CR_CERT_STATUS_A; else s->state=SSL3_ST_CR_KEY_EXCH_A; } else { skip = 1; s->state=SSL3_ST_CR_KEY_EXCH_A; } #else } else skip=1; s->state=SSL3_ST_CR_KEY_EXCH_A; #endif s->init_num=0; break; case SSL3_ST_CR_KEY_EXCH_A: case SSL3_ST_CR_KEY_EXCH_B: ret=ssl3_get_key_exchange(s); if (ret <= 0) goto end; s->state=SSL3_ST_CR_CERT_REQ_A; s->init_num=0; /* at this point we check that we have the * required stuff from the server */ if (!ssl3_check_cert_and_algorithm(s)) { ret= -1; goto end; } break; case SSL3_ST_CR_CERT_REQ_A: case SSL3_ST_CR_CERT_REQ_B: ret=ssl3_get_certificate_request(s); if (ret <= 0) goto end; s->state=SSL3_ST_CR_SRVR_DONE_A; s->init_num=0; break; case SSL3_ST_CR_SRVR_DONE_A: case SSL3_ST_CR_SRVR_DONE_B: ret=ssl3_get_server_done(s); if (ret <= 0) goto end; dtls1_stop_timer(s); if (s->s3->tmp.cert_req) s->s3->tmp.next_state=SSL3_ST_CW_CERT_A; else s->s3->tmp.next_state=SSL3_ST_CW_KEY_EXCH_A; s->init_num=0; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && state == SSL_ST_RENEGOTIATE) s->state=DTLS1_SCTP_ST_CR_READ_SOCK; else #endif s->state=s->s3->tmp.next_state; break; case SSL3_ST_CW_CERT_A: case SSL3_ST_CW_CERT_B: case SSL3_ST_CW_CERT_C: case SSL3_ST_CW_CERT_D: dtls1_start_timer(s); ret=dtls1_send_client_certificate(s); if (ret <= 0) goto end; s->state=SSL3_ST_CW_KEY_EXCH_A; s->init_num=0; break; case SSL3_ST_CW_KEY_EXCH_A: case SSL3_ST_CW_KEY_EXCH_B: dtls1_start_timer(s); ret=dtls1_send_client_key_exchange(s); if (ret <= 0) goto end; #ifndef OPENSSL_NO_SCTP /* Add new shared key for SCTP-Auth, * will be ignored if no SCTP used. */ snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), DTLS1_SCTP_AUTH_LABEL); SSL_export_keying_material(s, sctpauthkey, sizeof(sctpauthkey), labelbuffer, sizeof(labelbuffer), NULL, 0, 0); BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, sizeof(sctpauthkey), sctpauthkey); #endif /* EAY EAY EAY need to check for DH fix cert * sent back */ /* For TLS, cert_req is set to 2, so a cert chain * of nothing is sent, but no verify packet is sent */ if (s->s3->tmp.cert_req == 1) { s->state=SSL3_ST_CW_CERT_VRFY_A; } else { #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { s->d1->next_state=SSL3_ST_CW_CHANGE_A; s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; } else #endif s->state=SSL3_ST_CW_CHANGE_A; s->s3->change_cipher_spec=0; } s->init_num=0; break; case SSL3_ST_CW_CERT_VRFY_A: case SSL3_ST_CW_CERT_VRFY_B: dtls1_start_timer(s); ret=dtls1_send_client_verify(s); if (ret <= 0) goto end; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { s->d1->next_state=SSL3_ST_CW_CHANGE_A; s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; } else #endif s->state=SSL3_ST_CW_CHANGE_A; s->init_num=0; s->s3->change_cipher_spec=0; break; case SSL3_ST_CW_CHANGE_A: case SSL3_ST_CW_CHANGE_B: if (!s->hit) dtls1_start_timer(s); ret=dtls1_send_change_cipher_spec(s, SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); if (ret <= 0) goto end; #ifndef OPENSSL_NO_SCTP /* Change to new shared key of SCTP-Auth, * will be ignored if no SCTP used. */ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL); #endif s->state=SSL3_ST_CW_FINISHED_A; s->init_num=0; s->session->cipher=s->s3->tmp.new_cipher; #ifdef OPENSSL_NO_COMP s->session->compress_meth=0; #else if (s->s3->tmp.new_compression == NULL) s->session->compress_meth=0; else s->session->compress_meth= s->s3->tmp.new_compression->id; #endif if (!s->method->ssl3_enc->setup_key_block(s)) { ret= -1; goto end; } if (!s->method->ssl3_enc->change_cipher_state(s, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { ret= -1; goto end; } dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); break; case SSL3_ST_CW_FINISHED_A: case SSL3_ST_CW_FINISHED_B: if (!s->hit) dtls1_start_timer(s); ret=dtls1_send_finished(s, SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B, s->method->ssl3_enc->client_finished_label, s->method->ssl3_enc->client_finished_label_len); if (ret <= 0) goto end; s->state=SSL3_ST_CW_FLUSH; /* clear flags */ s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER; if (s->hit) { s->s3->tmp.next_state=SSL_ST_OK; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { s->d1->next_state = s->s3->tmp.next_state; s->s3->tmp.next_state=DTLS1_SCTP_ST_CW_WRITE_SOCK; } #endif if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) { s->state=SSL_ST_OK; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { s->d1->next_state = SSL_ST_OK; s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; } #endif s->s3->flags|=SSL3_FLAGS_POP_BUFFER; s->s3->delay_buf_pop_ret=0; } } else { #ifndef OPENSSL_NO_TLSEXT /* Allow NewSessionTicket if ticket expected */ if (s->tlsext_ticket_expected) s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A; else #endif s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A; } s->init_num=0; break; #ifndef OPENSSL_NO_TLSEXT case SSL3_ST_CR_SESSION_TICKET_A: case SSL3_ST_CR_SESSION_TICKET_B: ret=ssl3_get_new_session_ticket(s); if (ret <= 0) goto end; s->state=SSL3_ST_CR_FINISHED_A; s->init_num=0; break; case SSL3_ST_CR_CERT_STATUS_A: case SSL3_ST_CR_CERT_STATUS_B: ret=ssl3_get_cert_status(s); if (ret <= 0) goto end; s->state=SSL3_ST_CR_KEY_EXCH_A; s->init_num=0; break; #endif case SSL3_ST_CR_FINISHED_A: case SSL3_ST_CR_FINISHED_B: s->d1->change_cipher_spec_ok = 1; ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A, SSL3_ST_CR_FINISHED_B); if (ret <= 0) goto end; dtls1_stop_timer(s); if (s->hit) s->state=SSL3_ST_CW_CHANGE_A; else s->state=SSL_ST_OK; #ifndef OPENSSL_NO_SCTP if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && state == SSL_ST_RENEGOTIATE) { s->d1->next_state=s->state; s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; } #endif s->init_num=0; break; case SSL3_ST_CW_FLUSH: s->rwstate=SSL_WRITING; if (BIO_flush(s->wbio) <= 0) { /* If the write error was fatal, stop trying */ if (!BIO_should_retry(s->wbio)) { s->rwstate=SSL_NOTHING; s->state=s->s3->tmp.next_state; } ret= -1; goto end; } s->rwstate=SSL_NOTHING; s->state=s->s3->tmp.next_state; break; case SSL_ST_OK: /* clean a few things up */ ssl3_cleanup_key_block(s); #if 0 if (s->init_buf != NULL) { BUF_MEM_free(s->init_buf); s->init_buf=NULL; } #endif /* If we are not 'joining' the last two packets, * remove the buffering now */ if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER)) ssl_free_wbio_buffer(s); /* else do it later in ssl3_write */ s->init_num=0; s->renegotiate=0; s->new_session=0; ssl_update_cache(s,SSL_SESS_CACHE_CLIENT); if (s->hit) s->ctx->stats.sess_hit++; ret=1; /* s->server=0; */ s->handshake_func=dtls1_connect; s->ctx->stats.sess_connect_good++; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1); /* done with handshaking */ s->d1->handshake_read_seq = 0; s->d1->next_handshake_write_seq = 0; goto end; /* break; */ default: SSLerr(SSL_F_DTLS1_CONNECT,SSL_R_UNKNOWN_STATE); ret= -1; goto end; /* break; */ }
int verify_cookie_callback(SSL * ssl, const unsigned char *cookie, unsigned int cookie_len) { unsigned char *buffer, result[EVP_MAX_MD_SIZE]; unsigned int length, resultlength; union { struct sockaddr sa; struct sockaddr_in s4; struct sockaddr_in6 s6; } peer; /* If secret isn't initialized yet, the cookie can't be valid */ if (!cookie_initialized) return 0; /* Read peer information */ (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); /* Create buffer with peer's address and port */ length = 0; switch (peer.sa.sa_family) { case AF_INET: length += sizeof(struct in_addr); length += sizeof(peer.s4.sin_port); break; case AF_INET6: length += sizeof(struct in6_addr); length += sizeof(peer.s6.sin6_port); break; default: OPENSSL_assert(0); break; } buffer = malloc(length); if (buffer == NULL) { BIO_printf(bio_err, "out of memory\n"); return 0; } switch (peer.sa.sa_family) { case AF_INET: memcpy(buffer, &peer.s4.sin_port, sizeof(peer.s4.sin_port)); memcpy(buffer + sizeof(peer.s4.sin_port), &peer.s4.sin_addr, sizeof(struct in_addr)); break; case AF_INET6: memcpy(buffer, &peer.s6.sin6_port, sizeof(peer.s6.sin6_port)); memcpy(buffer + sizeof(peer.s6.sin6_port), &peer.s6.sin6_addr, sizeof(struct in6_addr)); break; default: OPENSSL_assert(0); break; } /* Calculate HMAC of buffer using the secret */ HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, buffer, length, result, &resultlength); free(buffer); if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0) return 1; return 0; }
static long ssl_ctrl(BIO *b, int cmd, long num, void *ptr) { SSL **sslp,*ssl; BIO_SSL *bs; BIO *dbio,*bio; long ret=1; bs=(BIO_SSL *)b->ptr; ssl=bs->ssl; if ((ssl == NULL) && (cmd != BIO_C_SET_SSL)) return(0); switch (cmd) { case BIO_CTRL_RESET: SSL_shutdown(ssl); if (ssl->handshake_func == ssl->method->ssl_connect) SSL_set_connect_state(ssl); else if (ssl->handshake_func == ssl->method->ssl_accept) SSL_set_accept_state(ssl); SSL_clear(ssl); if (b->next_bio != NULL) ret=BIO_ctrl(b->next_bio,cmd,num,ptr); else if (ssl->rbio != NULL) ret=BIO_ctrl(ssl->rbio,cmd,num,ptr); else ret=1; break; case BIO_CTRL_INFO: ret=0; break; case BIO_C_SSL_MODE: if (num) /* client mode */ SSL_set_connect_state(ssl); else SSL_set_accept_state(ssl); break; case BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT: ret=bs->renegotiate_timeout; if (num < 60) num=5; bs->renegotiate_timeout=(unsigned long)num; bs->last_time=(unsigned long)time(NULL); break; case BIO_C_SET_SSL_RENEGOTIATE_BYTES: ret=bs->renegotiate_count; if ((long)num >=512) bs->renegotiate_count=(unsigned long)num; break; case BIO_C_GET_SSL_NUM_RENEGOTIATES: ret=bs->num_renegotiates; break; case BIO_C_SET_SSL: if (ssl != NULL) { ssl_free(b); if (!ssl_new(b)) return 0; } b->shutdown=(int)num; ssl=(SSL *)ptr; ((BIO_SSL *)b->ptr)->ssl=ssl; bio=SSL_get_rbio(ssl); if (bio != NULL) { if (b->next_bio != NULL) BIO_push(bio,b->next_bio); b->next_bio=bio; CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO); } b->init=1; break; case BIO_C_GET_SSL: if (ptr != NULL) { sslp=(SSL **)ptr; *sslp=ssl; } else ret=0; break; case BIO_CTRL_GET_CLOSE: ret=b->shutdown; break; case BIO_CTRL_SET_CLOSE: b->shutdown=(int)num; break; case BIO_CTRL_WPENDING: ret=BIO_ctrl(ssl->wbio,cmd,num,ptr); break; case BIO_CTRL_PENDING: ret=SSL_pending(ssl); if (ret == 0) ret=BIO_pending(ssl->rbio); break; case BIO_CTRL_FLUSH: BIO_clear_retry_flags(b); ret=BIO_ctrl(ssl->wbio,cmd,num,ptr); BIO_copy_next_retry(b); break; case BIO_CTRL_PUSH: if ((b->next_bio != NULL) && (b->next_bio != ssl->rbio)) { SSL_set_bio(ssl,b->next_bio,b->next_bio); CRYPTO_add(&b->next_bio->references,1,CRYPTO_LOCK_BIO); } break; case BIO_CTRL_POP: /* ugly bit of a hack */ if (ssl->rbio != ssl->wbio) /* we are in trouble :-( */ { BIO_free_all(ssl->wbio); } if (b->next_bio != NULL) { CRYPTO_add(&b->next_bio->references,1,CRYPTO_LOCK_BIO); } ssl->wbio=NULL; ssl->rbio=NULL; break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); b->retry_reason=0; ret=(int)SSL_do_handshake(ssl); switch (SSL_get_error(ssl,(int)ret)) { case SSL_ERROR_WANT_READ: BIO_set_flags(b, BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_WRITE: BIO_set_flags(b, BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(b, BIO_FLAGS_IO_SPECIAL|BIO_FLAGS_SHOULD_RETRY); b->retry_reason=b->next_bio->retry_reason; break; default: break; } break; case BIO_CTRL_DUP: dbio=(BIO *)ptr; if (((BIO_SSL *)dbio->ptr)->ssl != NULL) SSL_free(((BIO_SSL *)dbio->ptr)->ssl); ((BIO_SSL *)dbio->ptr)->ssl=SSL_dup(ssl); ((BIO_SSL *)dbio->ptr)->renegotiate_count= ((BIO_SSL *)b->ptr)->renegotiate_count; ((BIO_SSL *)dbio->ptr)->byte_count= ((BIO_SSL *)b->ptr)->byte_count; ((BIO_SSL *)dbio->ptr)->renegotiate_timeout= ((BIO_SSL *)b->ptr)->renegotiate_timeout; ((BIO_SSL *)dbio->ptr)->last_time= ((BIO_SSL *)b->ptr)->last_time; ret=(((BIO_SSL *)dbio->ptr)->ssl != NULL); break; case BIO_C_GET_FD: ret=BIO_ctrl(ssl->rbio,cmd,num,ptr); break; case BIO_CTRL_SET_CALLBACK: { #if 0 /* FIXME: Should this be used? -- Richard Levitte */ SSLerr(SSL_F_SSL_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); ret = -1; #else ret=0; #endif } break; case BIO_CTRL_GET_CALLBACK: { void (**fptr)(const SSL *xssl,int type,int val); fptr=(void (**)(const SSL *xssl,int type,int val))ptr; *fptr=SSL_get_info_callback(ssl); } break; default: ret=BIO_ctrl(ssl->rbio,cmd,num,ptr); break; } return(ret); }
int DTLSv1_listen(SSL *s, BIO_ADDR *client) { int next, n, ret = 0, clearpkt = 0; unsigned char cookie[DTLS1_COOKIE_LENGTH]; unsigned char seq[SEQ_NUM_SIZE]; const unsigned char *data; unsigned char *p, *buf; unsigned long reclen, fragoff, fraglen, msglen; unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen; BIO *rbio, *wbio; BUF_MEM *bufm; BIO_ADDR *tmpclient = NULL; PACKET pkt, msgpkt, msgpayload, session, cookiepkt; /* Ensure there is no state left over from a previous invocation */ if (!SSL_clear(s)) return -1; ERR_clear_error(); rbio = SSL_get_rbio(s); wbio = SSL_get_wbio(s); if (!rbio || !wbio) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BIO_NOT_SET); return -1; } /* * We only peek at incoming ClientHello's until we're sure we are going to * to respond with a HelloVerifyRequest. If its a ClientHello with a valid * cookie then we leave it in the BIO for accept to handle. */ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL); /* * Note: This check deliberately excludes DTLS1_BAD_VER because that version * requires the MAC to be calculated *including* the first ClientHello * (without the cookie). Since DTLSv1_listen is stateless that cannot be * supported. DTLS1_BAD_VER must use cookies in a stateful manner (e.g. via * SSL_accept) */ if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNSUPPORTED_SSL_VERSION); return -1; } if (s->init_buf == NULL) { if ((bufm = BUF_MEM_new()) == NULL) { SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE); return -1; } if (!BUF_MEM_grow(bufm, SSL3_RT_MAX_PLAIN_LENGTH)) { BUF_MEM_free(bufm); SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE); return -1; } s->init_buf = bufm; } buf = (unsigned char *)s->init_buf->data; do { /* Get a packet */ clear_sys_error(); /* * Technically a ClientHello could be SSL3_RT_MAX_PLAIN_LENGTH * + DTLS1_RT_HEADER_LENGTH bytes long. Normally init_buf does not store * the record header as well, but we do here. We've set up init_buf to * be the standard size for simplicity. In practice we shouldn't ever * receive a ClientHello as long as this. If we do it will get dropped * in the record length check below. */ n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH); if (n <= 0) { if (BIO_should_retry(rbio)) { /* Non-blocking IO */ goto end; } return -1; } /* If we hit any problems we need to clear this packet from the BIO */ clearpkt = 1; if (!PACKET_buf_init(&pkt, buf, n)) { SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR); return -1; } /* * Parse the received record. If there are any problems with it we just * dump it - with no alert. RFC6347 says this "Unlike TLS, DTLS is * resilient in the face of invalid records (e.g., invalid formatting, * length, MAC, etc.). In general, invalid records SHOULD be silently * discarded, thus preserving the association; however, an error MAY be * logged for diagnostic purposes." */ /* this packet contained a partial record, dump it */ if (n < DTLS1_RT_HEADER_LENGTH) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_RECORD_TOO_SMALL); goto end; } if (s->msg_callback) s->msg_callback(0, 0, SSL3_RT_HEADER, buf, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); /* Get the record header */ if (!PACKET_get_1(&pkt, &rectype) || !PACKET_get_1(&pkt, &versmajor)) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } if (rectype != SSL3_RT_HANDSHAKE) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE); goto end; } /* * Check record version number. We only check that the major version is * the same. */ if (versmajor != DTLS1_VERSION_MAJOR) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BAD_PROTOCOL_VERSION_NUMBER); goto end; } if (!PACKET_forward(&pkt, 1) /* Save the sequence number: 64 bits, with top 2 bytes = epoch */ || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE) || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } /* * We allow data remaining at the end of the packet because there could * be a second record (but we ignore it) */ /* This is an initial ClientHello so the epoch has to be 0 */ if (seq[0] != 0 || seq[1] != 0) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE); goto end; } /* Get a pointer to the raw message for the later callback */ data = PACKET_data(&msgpkt); /* Finished processing the record header, now process the message */ if (!PACKET_get_1(&msgpkt, &msgtype) || !PACKET_get_net_3(&msgpkt, &msglen) || !PACKET_get_net_2(&msgpkt, &msgseq) || !PACKET_get_net_3(&msgpkt, &fragoff) || !PACKET_get_net_3(&msgpkt, &fraglen) || !PACKET_get_sub_packet(&msgpkt, &msgpayload, fraglen) || PACKET_remaining(&msgpkt) != 0) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } if (msgtype != SSL3_MT_CLIENT_HELLO) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE); goto end; } /* Message sequence number can only be 0 or 1 */ if (msgseq > 2) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_INVALID_SEQUENCE_NUMBER); goto end; } /* * We don't support fragment reassembly for ClientHellos whilst * listening because that would require server side state (which is * against the whole point of the ClientHello/HelloVerifyRequest * mechanism). Instead we only look at the first ClientHello fragment * and require that the cookie must be contained within it. */ if (fragoff != 0 || fraglen > msglen) { /* Non initial ClientHello fragment (or bad fragment) */ SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_FRAGMENTED_CLIENT_HELLO); goto end; } if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data, fraglen + DTLS1_HM_HEADER_LENGTH, s, s->msg_callback_arg); if (!PACKET_get_net_2(&msgpayload, &clientvers)) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } /* * Verify client version is supported */ if (DTLS_VERSION_LT(clientvers, (unsigned int)s->method->version) && s->method->version != DTLS_ANY_VERSION) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_WRONG_VERSION_NUMBER); goto end; } if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE) || !PACKET_get_length_prefixed_1(&msgpayload, &session) || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) { /* * Could be malformed or the cookie does not fit within the initial * ClientHello fragment. Either way we can't handle it. */ SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } /* * Check if we have a cookie or not. If not we need to send a * HelloVerifyRequest. */ if (PACKET_remaining(&cookiepkt) == 0) { next = LISTEN_SEND_VERIFY_REQUEST; } else { /* * We have a cookie, so lets check it. */ if (s->ctx->app_verify_cookie_cb == NULL) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_NO_VERIFY_COOKIE_CALLBACK); /* This is fatal */ return -1; } if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookiepkt), PACKET_remaining(&cookiepkt)) == 0) { /* * We treat invalid cookies in the same was as no cookie as * per RFC6347 */ next = LISTEN_SEND_VERIFY_REQUEST; } else { /* Cookie verification succeeded */ next = LISTEN_SUCCESS; } } if (next == LISTEN_SEND_VERIFY_REQUEST) { /* * There was no cookie in the ClientHello so we need to send a * HelloVerifyRequest. If this fails we do not worry about trying * to resend, we just drop it. */ /* * Dump the read packet, we don't need it any more. Ignore return * value */ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL); BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH); BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL); /* Generate the cookie */ if (s->ctx->app_gen_cookie_cb == NULL || s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0 || cookielen > 255) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_COOKIE_GEN_CALLBACK_FAILURE); /* This is fatal */ return -1; } p = &buf[DTLS1_RT_HEADER_LENGTH]; msglen = dtls_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH, cookie, cookielen); *p++ = DTLS1_MT_HELLO_VERIFY_REQUEST; /* Message length */ l2n3(msglen, p); /* Message sequence number is always 0 for a HelloVerifyRequest */ s2n(0, p); /* * We never fragment a HelloVerifyRequest, so fragment offset is 0 * and fragment length is message length */ l2n3(0, p); l2n3(msglen, p); /* Set reclen equal to length of whole handshake message */ reclen = msglen + DTLS1_HM_HEADER_LENGTH; /* Add the record header */ p = buf; *(p++) = SSL3_RT_HANDSHAKE; /* * Special case: for hello verify request, client version 1.0 and we * haven't decided which version to use yet send back using version * 1.0 header: otherwise some clients will ignore it. */ if (s->method->version == DTLS_ANY_VERSION) { *(p++) = DTLS1_VERSION >> 8; *(p++) = DTLS1_VERSION & 0xff; } else { *(p++) = s->version >> 8; *(p++) = s->version & 0xff; } /* * Record sequence number is always the same as in the received * ClientHello */ memcpy(p, seq, SEQ_NUM_SIZE); p += SEQ_NUM_SIZE; /* Length */ s2n(reclen, p); /* * Set reclen equal to length of whole record including record * header */ reclen += DTLS1_RT_HEADER_LENGTH; if (s->msg_callback) s->msg_callback(1, 0, SSL3_RT_HEADER, buf, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); if ((tmpclient = BIO_ADDR_new()) == NULL) { SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE); goto end; } /* * This is unnecessary if rbio and wbio are one and the same - but * maybe they're not. We ignore errors here - some BIOs do not * support this. */ if (BIO_dgram_get_peer(rbio, tmpclient) > 0) { (void)BIO_dgram_set_peer(wbio, tmpclient); } BIO_ADDR_free(tmpclient); tmpclient = NULL; if (BIO_write(wbio, buf, reclen) < (int)reclen) { if (BIO_should_retry(wbio)) { /* * Non-blocking IO...but we're stateless, so we're just * going to drop this packet. */ goto end; } return -1; } if (BIO_flush(wbio) <= 0) { if (BIO_should_retry(wbio)) { /* * Non-blocking IO...but we're stateless, so we're just * going to drop this packet. */ goto end; } return -1; } }