static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len) { int iostate = 1; fd_set fdset; struct timeval tv; int err = WSAEWOULDBLOCK; int rv; int sock = fb->fd_in; SSL *ssl; int retry; ssl = ap_ctx_get(fb->ctx, "ssl"); if (!(tv.tv_sec = ap_check_alarm())) return (SSL_read(ssl, buf, len)); rv = ioctlsocket(sock, FIONBIO, &iostate); iostate = 0; ap_assert(!rv); rv = SSL_read(ssl, buf, len); if (rv <= 0) { if (BIO_sock_should_retry(rv)) { do { retry = 0; FD_ZERO(&fdset); FD_SET((unsigned int)sock, &fdset); tv.tv_usec = 0; rv = select(FD_SETSIZE, &fdset, NULL, NULL, &tv); if (rv == SOCKET_ERROR) err = WSAGetLastError(); else if (rv == 0) { ioctlsocket(sock, FIONBIO, &iostate); ap_check_alarm(); WSASetLastError(WSAEWOULDBLOCK); return (SOCKET_ERROR); } else { rv = SSL_read(ssl, buf, len); if (rv == SOCKET_ERROR) { if (BIO_sock_should_retry(rv)) { ap_log_error(APLOG_MARK,APLOG_DEBUG, NULL, "select claimed we could read, " "but in fact we couldn't. " "This is a bug in Windows."); retry = 1; Sleep(100); } else { err = WSAGetLastError(); } } } } while(retry); } } ioctlsocket(sock, FIONBIO, &iostate); if (rv == SOCKET_ERROR) WSASetLastError(err); return (rv); }
/*- * BIO_accept_ex - Accept new incoming connections * @sock: the listening socket * @addr: the BIO_ADDR to store the peer address in * @options: BIO socket options, applied on the accepted socket. * */ int BIO_accept_ex(int accept_sock, BIO_ADDR *addr_, int options) { socklen_t len; int accepted_sock; BIO_ADDR locaddr; BIO_ADDR *addr = addr_ == NULL ? &locaddr : addr_; len = sizeof(*addr); accepted_sock = accept(accept_sock, BIO_ADDR_sockaddr_noconst(addr), &len); if (accepted_sock == -1) { if (!BIO_sock_should_retry(accepted_sock)) { SYSerr(SYS_F_ACCEPT, get_last_socket_error()); BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR); } return INVALID_SOCKET; } if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) { closesocket(accepted_sock); return INVALID_SOCKET; } return accepted_sock; }
static int dgram_write(BIO *b, const char *in, int inl) { int ret; bio_dgram_data *data = (bio_dgram_data *)b->ptr; clear_socket_error(); if ( data->connected ) ret=writesocket(b->num,in,inl); else #if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) ret=sendto(b->num, (char *)in, inl, 0, &data->peer, sizeof(data->peer)); #else ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer)); #endif BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_sock_should_retry(ret)) { BIO_set_retry_write(b); data->_errno = get_last_socket_error(); #if 0 /* higher layers are responsible for querying MTU, if necessary */ if ( data->_errno == EMSGSIZE) /* retrieve the new MTU */ BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); #endif } } return(ret); }
static int fd_read(BIO *b, char *out,int outl) #endif { int ret=0; if (out != NULL) { #ifndef BIO_FD clear_socket_error(); ret=readsocket(b->num,out,outl); #else clear_sys_error(); ret=read(b->num,out,outl); #endif BIO_clear_retry_flags(b); if (ret <= 0) { #ifndef BIO_FD if (BIO_sock_should_retry(ret)) #else if (BIO_fd_should_retry(ret)) #endif BIO_set_retry_read(b); } } return(ret); }
static int conn_read(BIO *b, char *out, int outl) { int ret=0; BIO_CONNECT *data; data=(BIO_CONNECT *)b->ptr; if (data->state != BIO_CONN_S_OK) { ret=conn_state(b,data); if (ret <= 0) return(ret); } if (out != NULL) { clear_socket_error(); ret=readsocket(b->num,out,outl); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_sock_should_retry(ret)) BIO_set_retry_read(b); } } return(ret); }
int BIO_accept(int sock, char **ip_port) { BIO_ADDR res; int ret = -1; ret = BIO_accept_ex(sock, &res, 0); if (ret == (int)INVALID_SOCKET) { if (BIO_sock_should_retry(ret)) { ret = -2; goto end; } SYSerr(SYS_F_ACCEPT, get_last_socket_error()); BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR); goto end; } if (ip_port != NULL) { char *host = BIO_ADDR_hostname_string(&res, 1); char *port = BIO_ADDR_service_string(&res, 1); *ip_port = OPENSSL_zalloc(strlen(host) + strlen(port) + 2); strcpy(*ip_port, host); strcat(*ip_port, ":"); strcat(*ip_port, port); OPENSSL_free(host); OPENSSL_free(port); } end: return ret; }
/*- * doConnection - make a connection * Args: * scon = earlier ssl connection for session id, or NULL * Returns: * SSL * = the connection pointer. */ static SSL *doConnection(SSL *scon) { BIO *conn; SSL *serverCon; int width, i; fd_set readfds; if ((conn = BIO_new(BIO_s_connect())) == NULL) return (NULL); /* BIO_set_conn_port(conn,port);*/ BIO_set_conn_hostname(conn, host); if (scon == NULL) serverCon = SSL_new(tm_ctx); else { serverCon = scon; SSL_set_connect_state(serverCon); } SSL_set_bio(serverCon, conn, conn); /* ok, lets connect */ for (;;) { i = SSL_connect(serverCon); if (BIO_sock_should_retry(i)) { BIO_printf(bio_err, "DELAY\n"); i = SSL_get_fd(serverCon); width = i + 1; FD_ZERO(&readfds); openssl_fdset(i, &readfds); /* * Note: under VMS with SOCKETSHR the 2nd parameter is currently * of type (int *) whereas under other systems it is (void *) if * you don't have a cast it will choke the compiler: if you do * have a cast then you can either go for (int *) or (void *). */ select(width, (void *)&readfds, NULL, NULL, NULL); continue; } break; } if (i <= 0) { BIO_printf(bio_err, "ERROR\n"); if (verify_error != X509_V_OK) BIO_printf(bio_err, "verify error:%s\n", X509_verify_cert_error_string(verify_error)); else ERR_print_errors(bio_err); if (scon == NULL) SSL_free(serverCon); return NULL; } return serverCon; }
int OpenSSLUtils::getBioShouldRetryWrite(int r) { int ret = 0; #if defined(OPENSSL_IS_BORINGSSL) ret = boringssl_bio_fd_should_retry(r); #else ret = BIO_sock_should_retry(r); #endif return ret; }
/*********************************************************************** * doConnection - make a connection * Args: * scon = earlier ssl connection for session id, or NULL * Returns: * SSL * = the connection pointer. */ static SSL * doConnection(SSL * scon) { BIO *conn; SSL *serverCon; int width, i; fd_set readfds; if ((conn = BIO_new(BIO_s_connect())) == NULL) return (NULL); /* BIO_set_conn_port(conn,port);*/ BIO_set_conn_hostname(conn, host); if (scon == NULL) serverCon = SSL_new(tm_ctx); else { serverCon = scon; SSL_set_connect_state(serverCon); } SSL_set_bio(serverCon, conn, conn); #if 0 if (scon != NULL) SSL_set_session(serverCon, SSL_get_session(scon)); #endif /* ok, lets connect */ for (;;) { i = SSL_connect(serverCon); if (BIO_sock_should_retry(i)) { BIO_printf(bio_err, "DELAY\n"); i = SSL_get_fd(serverCon); width = i + 1; FD_ZERO(&readfds); FD_SET(i, &readfds); select(width, &readfds, NULL, NULL, NULL); continue; } break; } if (i <= 0) { BIO_printf(bio_err, "ERROR\n"); if (verify_error != X509_V_OK) BIO_printf(bio_err, "verify error:%s\n", X509_verify_cert_error_string(verify_error)); else ERR_print_errors(bio_err); if (scon == NULL) SSL_free(serverCon); return NULL; } return serverCon; }
/*********************************************************************** * doConnection - make a connection * Args: * scon = earlier ssl connection for session id, or NULL * Returns: * SSL * = the connection pointer. */ static SSL * doConnection(SSL * scon) { struct pollfd pfd[1]; SSL *serverCon; BIO *conn; long verify_error; int i; if ((conn = BIO_new(BIO_s_connect())) == NULL) return (NULL); /* BIO_set_conn_port(conn,port);*/ BIO_set_conn_hostname(conn, s_time_config.host); if (scon == NULL) serverCon = SSL_new(tm_ctx); else { serverCon = scon; SSL_set_connect_state(serverCon); } SSL_set_bio(serverCon, conn, conn); /* ok, lets connect */ for (;;) { i = SSL_connect(serverCon); if (BIO_sock_should_retry(i)) { BIO_printf(bio_err, "DELAY\n"); i = SSL_get_fd(serverCon); pfd[0].fd = i; pfd[0].events = POLLIN; poll(pfd, 1, -1); continue; } break; } if (i <= 0) { BIO_printf(bio_err, "ERROR\n"); verify_error = SSL_get_verify_result(serverCon); if (verify_error != X509_V_OK) BIO_printf(bio_err, "verify error:%s\n", X509_verify_cert_error_string(verify_error)); else ERR_print_errors(bio_err); if (scon == NULL) SSL_free(serverCon); return NULL; } return serverCon; }
static int sock_write(BIO *b, const char *in, int inl) { int ret; clear_socket_error(); ret = writesocket(b->num, in, inl); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_sock_should_retry(ret)) BIO_set_retry_write(b); } return (ret); }
static int sock_read(BIO *b, char *out, int outl) { int ret = 0; if (out != NULL) { clear_socket_error(); ret = readsocket(b->num, out, outl); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_sock_should_retry(ret)) BIO_set_retry_read(b); } } return (ret); }
int BIO_accept(int sock, char **addr) { int ret=INVALID_SOCKET; static struct sockaddr_in from; unsigned long l; unsigned short port; int len; char *p; memset((char *)&from,0,sizeof(from)); len=sizeof(from); /* Note: under VMS with SOCKETSHR the fourth parameter is currently * of type (int *) whereas under other systems it is (void *) if * you don't have a cast it will choke the compiler: if you do * have a cast then you can either go for (int *) or (void *). */ ret=accept(sock,(struct sockaddr *)&from,(void *)&len); if (ret == INVALID_SOCKET) { if(BIO_sock_should_retry(ret)) return -2; SYSerr(SYS_F_ACCEPT,get_last_socket_error()); BIOerr(BIO_F_BIO_ACCEPT,BIO_R_ACCEPT_ERROR); goto end; } if (addr == NULL) goto end; l=ntohl(from.sin_addr.s_addr); port=ntohs(from.sin_port); if (*addr == NULL) { if ((p=OPENSSL_malloc(24)) == NULL) { BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE); goto end; } *addr=p; } BIO_snprintf(*addr,24,"%d.%d.%d.%d:%d", (unsigned char)(l>>24L)&0xff, (unsigned char)(l>>16L)&0xff, (unsigned char)(l>> 8L)&0xff, (unsigned char)(l )&0xff, port); end: return(ret); }
int ipfix_ssl_init_con( SSL *con ) { extern FILE *mlog_fp; // todo: see if this is working int i; char *str; long verify_error; char buf[100]; if ((i=SSL_accept(con)) <= 0) { if (BIO_sock_should_retry(i)) { mlogf( 0, "[ipfix_ssl_init] DELAY\n"); return -1; } mlogf( 0, "[ipfix_ssl_init] ERROR\n"); verify_error=SSL_get_verify_result( con ); if (verify_error != X509_V_OK) { mlogf( 0, "[ipfix_ssl_init] verify error: %s\n", X509_verify_cert_error_string(verify_error)); } else ERR_print_errors_fp( mlog_fp ); return -1; } if ( 1 <= mlog_get_vlevel() ) { PEM_write_SSL_SESSION( mlog_fp, SSL_get_session(con)); if ( SSL_get_shared_ciphers(con, buf, sizeof buf) != NULL) { mlogf( 3, "[ipfix] Shared ciphers:%s\n", buf); } str=(char*)SSL_CIPHER_get_name( SSL_get_current_cipher(con) ); mlogf( 3, "[ipfix] CIPHER is %s\n",(str != NULL)?str:"(NONE)"); if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) & TLS1_FLAGS_TLS_PADDING_BUG) { mlogf( 1, "[ipfix] Peer has incorrect TLSv1 block padding\n"); } } return 0; }
/*- * BIO_connect - connect to an address * @sock: the socket to connect with * @addr: the address to connect to * @options: BIO socket options * * Connects to the address using the given socket and options. * * Options can be a combination of the following: * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. * - BIO_SOCK_NODELAY: don't delay small messages. * * options holds BIO socket options that can be used * You should call this for every address returned by BIO_lookup * until the connection is successful. * * Returns 1 on success or 0 on failure. On failure errno is set * and an error status is added to the OpenSSL error stack. */ int BIO_connect(int sock, const BIO_ADDR *addr, int options) { const int on = 1; if (sock == -1) { BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET); return 0; } if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) return 0; if (options & BIO_SOCK_KEEPALIVE) { if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const void *)&on, sizeof(on)) != 0) { SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE); return 0; } } if (options & BIO_SOCK_NODELAY) { if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const void *)&on, sizeof(on)) != 0) { SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY); return 0; } } if (connect(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) == -1) { if (!BIO_sock_should_retry(-1)) { SYSerr(SYS_F_CONNECT, get_last_socket_error()); BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR); } return 0; } return 1; }
static int conn_write(BIO *b, const char *in, int inl) { int ret; BIO_CONNECT *data; data=(BIO_CONNECT *)b->ptr; if (data->state != BIO_CONN_S_OK) { ret=conn_state(b,data); if (ret <= 0) return(ret); } clear_socket_error(); ret=writesocket(b->num,in,inl); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_sock_should_retry(ret)) BIO_set_retry_write(b); } return(ret); }
static int fd_write(BIO *b, const char *in, int inl) #endif { int ret; #ifndef BIO_FD clear_socket_error(); ret=writesocket(b->num,in,inl); #else clear_sys_error(); ret=write(b->num,in,inl); #endif BIO_clear_retry_flags(b); if (ret <= 0) { #ifndef BIO_FD if (BIO_sock_should_retry(ret)) #else if (BIO_fd_should_retry(ret)) #endif BIO_set_retry_write(b); } return(ret); }
int BIO_accept(int sock, char **addr) { int ret = -1; unsigned long l; unsigned short port; char *p, *tmp; struct { socklen_t len; union { struct sockaddr sa; struct sockaddr_in sa_in; struct sockaddr_in6 sa_in6; } from; } sa; sa.len = sizeof(sa.from); memset(&sa.from, 0, sizeof(sa.from)); ret = accept(sock, &sa.from.sa, &sa.len); if (ret == -1) { if (BIO_sock_should_retry(ret)) return -2; SYSerr(SYS_F_ACCEPT, errno); BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR); goto end; } if (addr == NULL) goto end; #ifdef EAI_FAMILY do { char h[NI_MAXHOST], s[NI_MAXSERV]; size_t nl; if (getnameinfo(&sa.from.sa, sa.len, h, sizeof(h), s, sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV)) break; nl = strlen(h) + strlen(s) + 2; p = *addr; if (p) { *p = '\0'; if (!(tmp = realloc(p, nl))) { close(ret); ret = -1; free(p); *addr = NULL; BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); goto end; } p = tmp; } else { p = malloc(nl); } if (p == NULL) { close(ret); ret = -1; BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); goto end; } *addr = p; snprintf(*addr, nl, "%s:%s", h, s); goto end; } while (0); #endif if (sa.from.sa.sa_family != AF_INET) goto end; l = ntohl(sa.from.sa_in.sin_addr.s_addr); port = ntohs(sa.from.sa_in.sin_port); if (*addr == NULL) { if ((p = malloc(24)) == NULL) { close(ret); ret = -1; BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); goto end; } *addr = p; } snprintf(*addr, 24, "%d.%d.%d.%d:%d", (unsigned char)(l >> 24L) & 0xff, (unsigned char)(l >> 16L) & 0xff, (unsigned char)(l >> 8L) & 0xff, (unsigned char)(l) & 0xff, port); end: return (ret); }
static int acpt_state(BIO *b, BIO_ACCEPT *c) { BIO *bio = NULL, *dbio; int s = -1, ret = -1; for (;;) { switch (c->state) { case ACPT_S_BEFORE: if (c->param_addr == NULL && c->param_serv == NULL) { BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED); ERR_add_error_data(4, "hostname=", c->param_addr, " service=", c->param_serv); goto exit_loop; } /* Because we're starting a new bind, any cached name and serv * are now obsolete and need to be cleaned out. * QUESTION: should this be done in acpt_close_socket() instead? */ OPENSSL_free(c->cache_accepting_name); c->cache_accepting_name = NULL; OPENSSL_free(c->cache_accepting_serv); c->cache_accepting_serv = NULL; OPENSSL_free(c->cache_peer_name); c->cache_peer_name = NULL; OPENSSL_free(c->cache_peer_serv); c->cache_peer_serv = NULL; c->state = ACPT_S_GET_ADDR; break; case ACPT_S_GET_ADDR: { int family = AF_UNSPEC; switch (c->accept_family) { case BIO_FAMILY_IPV6: if (1) { /* This is a trick we use to avoid bit rot. * at least the "else" part will always be * compiled. */ #ifdef AF_INET6 family = AF_INET6; } else { #endif BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY); goto exit_loop; } break; case BIO_FAMILY_IPV4: family = AF_INET; break; case BIO_FAMILY_IPANY: family = AF_UNSPEC; break; default: BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY); goto exit_loop; } if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER, family, SOCK_STREAM, &c->addr_first) == 0) goto exit_loop; } if (c->addr_first == NULL) { BIOerr(BIO_F_ACPT_STATE, BIO_R_LOOKUP_RETURNED_NOTHING); goto exit_loop; } /* We're currently not iterating, but set this as preparation * for possible future development in that regard */ c->addr_iter = c->addr_first; c->state = ACPT_S_CREATE_SOCKET; break; case ACPT_S_CREATE_SOCKET: ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter), BIO_ADDRINFO_socktype(c->addr_iter), BIO_ADDRINFO_protocol(c->addr_iter), 0); if (ret == (int)INVALID_SOCKET) { SYSerr(SYS_F_SOCKET, get_last_socket_error()); ERR_add_error_data(4, "hostname=", c->param_addr, " service=", c->param_serv); BIOerr(BIO_F_ACPT_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET); goto exit_loop; } c->accept_sock = ret; b->num = ret; c->state = ACPT_S_LISTEN; break; case ACPT_S_LISTEN: { if (!BIO_listen(c->accept_sock, BIO_ADDRINFO_address(c->addr_iter), c->bind_mode)) { BIO_closesocket(c->accept_sock); goto exit_loop; } } { union BIO_sock_info_u info; info.addr = &c->cache_accepting_addr; if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS, &info)) { BIO_closesocket(c->accept_sock); goto exit_loop; } } c->cache_accepting_name = BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1); c->cache_accepting_serv = BIO_ADDR_service_string(&c->cache_accepting_addr, 1); c->state = ACPT_S_ACCEPT; s = -1; ret = 1; goto end; case ACPT_S_ACCEPT: if (b->next_bio != NULL) { c->state = ACPT_S_OK; break; } BIO_clear_retry_flags(b); b->retry_reason = 0; OPENSSL_free(c->cache_peer_name); c->cache_peer_name = NULL; OPENSSL_free(c->cache_peer_serv); c->cache_peer_serv = NULL; s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr, c->accepted_mode); /* If the returned socket is invalid, this might still be * retryable */ if (s < 0) { if (BIO_sock_should_retry(s)) { BIO_set_retry_special(b); b->retry_reason = BIO_RR_ACCEPT; goto end; } } /* If it wasn't retryable, we fail */ if (s < 0) { ret = s; goto exit_loop; } bio = BIO_new_socket(s, BIO_CLOSE); if (bio == NULL) goto exit_loop; BIO_set_callback(bio, BIO_get_callback(b)); BIO_set_callback_arg(bio, BIO_get_callback_arg(b)); /* * If the accept BIO has an bio_chain, we dup it and put the new * socket at the end. */ if (c->bio_chain != NULL) { if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) goto exit_loop; if (!BIO_push(dbio, bio)) goto exit_loop; bio = dbio; } if (BIO_push(b, bio) == NULL) goto exit_loop; c->cache_peer_name = BIO_ADDR_hostname_string(&c->cache_peer_addr, 1); c->cache_peer_serv = BIO_ADDR_service_string(&c->cache_peer_addr, 1); c->state = ACPT_S_OK; bio = NULL; ret = 1; goto end; case ACPT_S_OK: if (b->next_bio == NULL) { c->state = ACPT_S_ACCEPT; break; } ret = 1; goto end; default: ret = 0; goto end; } } exit_loop: if (bio != NULL) BIO_free(bio); else if (s >= 0) BIO_closesocket(s); end: return ret; }
static int init_ssl_connection(SSL *con) { int i; #ifdef DEBUG const char *str; X509 *peer; static char buf[BUFSIZ]; #endif long verify_error; int err = 0; if ((i = SSL_accept(con)) <= 0) { err = SSL_get_error (con, i); if ((SSL_ERROR_WANT_READ == err) || (SSL_ERROR_WANT_WRITE == err)) fprintf (stderr, "%s: %s(): Error [SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE]\n", \ __FILE__, __func__); if (BIO_sock_should_retry (i)) { BIO_printf(bio_s_out, "DELAY\n"); return 1; } BIO_printf(bio_err, "ERROR\n"); verify_error = SSL_get_verify_result (con); if (verify_error != X509_V_OK) { BIO_printf(bio_err,"verify error:%s\n", X509_verify_cert_error_string(verify_error)); } else { fprintf (stderr, "%s: %s(): X509_V_OK but error\n", __FILE__, __func__); ERR_print_errors (bio_err); } return 0; } #ifdef DEBUG PEM_write_bio_SSL_SESSION (bio_s_out, SSL_get_session (con)); peer = SSL_get_peer_certificate (con); if (NULL != peer) { BIO_printf (bio_s_out, "Client certificate\n"); PEM_write_bio_X509 (bio_s_out, peer); X509_NAME_oneline (X509_get_subject_name (peer), buf, sizeof buf); BIO_printf (bio_s_out, "subject = %s\n", buf); X509_NAME_oneline (X509_get_issuer_name (peer), buf, sizeof buf); BIO_printf (bio_s_out, "issuer = %s\n", buf); X509_free(peer); } if (SSL_get_shared_ciphers (con, buf, sizeof buf) != NULL) BIO_printf (bio_s_out, "Shared ciphers: %s\n", buf); str = SSL_CIPHER_get_name (SSL_get_current_cipher (con)); BIO_printf (bio_s_out, "CIPHER is %s\n", (str != NULL) ? str : "(NONE)"); #endif if (con->hit) BIO_printf (bio_s_out, "Reused session-id\n"); if (SSL_ctrl (con, SSL_CTRL_GET_FLAGS, 0, NULL) & TLS1_FLAGS_TLS_PADDING_BUG) BIO_printf (bio_s_out, "Peer has incorrect TLSv1 block padding\n"); return 1; }
int BIO_accept(int sock, char **addr) { int ret=INVALID_SOCKET; unsigned long l; unsigned short port; char *p; struct { /* * As for following union. Trouble is that there are platforms * that have socklen_t and there are platforms that don't, on * some platforms socklen_t is int and on some size_t. So what * one can do? One can cook #ifdef spaghetti, which is nothing * but masochistic. Or one can do union between int and size_t. * One naturally does it primarily for 64-bit platforms where * sizeof(int) != sizeof(size_t). But would it work? Note that * if size_t member is initialized to 0, then later int member * assignment naturally does the job on little-endian platforms * regardless accept's expectations! What about big-endians? * If accept expects int*, then it works, and if size_t*, then * length value would appear as unreasonably large. But this * won't prevent it from filling in the address structure. The * trouble of course would be if accept returns more data than * actual buffer can accomodate and overwrite stack... That's * where early OPENSSL_assert comes into picture. Besides, the * only 64-bit big-endian platform found so far that expects * size_t* is HP-UX, where stack grows towards higher address. * <appro> */ union { size_t s; int i; } len; union { struct sockaddr sa; struct sockaddr_in sa_in; #if OPENSSL_USE_IPV6 struct sockaddr_in6 sa_in6; #endif } from; } sa; sa.len.s=0; sa.len.i=sizeof(sa.from); memset(&sa.from,0,sizeof(sa.from)); ret=accept(sock,&sa.from.sa,(void *)&sa.len); if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0) { OPENSSL_assert(sa.len.s<=sizeof(sa.from)); sa.len.i = (unsigned int)sa.len.s; } if (ret == INVALID_SOCKET) { if(BIO_sock_should_retry(ret)) return -2; SYSerr(SYS_F_ACCEPT,get_last_socket_error()); BIOerr(BIO_F_BIO_ACCEPT,BIO_R_ACCEPT_ERROR); goto end; } if (addr == NULL) goto end; #ifdef EAI_FAMILY do { char h[NI_MAXHOST],s[NI_MAXSERV]; size_t nl; static union { void *p; int (*f)(const struct sockaddr *,size_t/*socklen_t*/, char *,size_t,char *,size_t,int); } p_getnameinfo = {NULL}; /* 2nd argument to getnameinfo is specified to * be socklen_t. Unfortunately there is a number * of environments where socklen_t is not defined. * As it's passed by value, it's safe to pass it * as size_t... <appro> */ if (p_getnameinfo.p==NULL) { if ((p_getnameinfo.p=DSO_global_lookup("getnameinfo"))==NULL) p_getnameinfo.p=(void*)-1; } if (p_getnameinfo.p==(void *)-1) break; if ((*p_getnameinfo.f)(&sa.from.sa,sa.len.i,h,sizeof(h),s,sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV)) break; nl = strlen(h)+strlen(s)+2; p = *addr; if (p) { *p = '\0'; p = OPENSSL_realloc(p,nl); } else { p = OPENSSL_malloc(nl); } if (p==NULL) { BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE); goto end; } *addr = p; BIO_snprintf(*addr,nl,"%s:%s",h,s); goto end; } while(0); #endif if (sa.from.sa.sa_family != AF_INET) goto end; l=ntohl(sa.from.sa_in.sin_addr.s_addr); port=ntohs(sa.from.sa_in.sin_port); if (*addr == NULL) { if ((p=OPENSSL_malloc(24)) == NULL) { BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE); goto end; } *addr=p; } BIO_snprintf(*addr,24,"%d.%d.%d.%d:%d", (unsigned char)(l>>24L)&0xff, (unsigned char)(l>>16L)&0xff, (unsigned char)(l>> 8L)&0xff, (unsigned char)(l )&0xff, port); end: return(ret); }
static int conn_state(BIO *b, BIO_CONNECT *c) { int ret= -1,i; unsigned long l; char *p,*q; int (*cb)()=NULL; if (c->info_callback != NULL) cb=c->info_callback; for (;;) { switch (c->state) { case BIO_CONN_S_BEFORE: p=c->param_hostname; if (p == NULL) { BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTNAME_SPECIFIED); goto exit_loop; } for ( ; *p != '\0'; p++) { if ((*p == ':') || (*p == '/')) break; } i= *p; if ((i == ':') || (i == '/')) { *(p++)='\0'; if (i == ':') { for (q=p; *q; q++) if (*q == '/') { *q='\0'; break; } if (c->param_port != NULL) OPENSSL_free(c->param_port); c->param_port=BUF_strdup(p); } } if (c->param_port == NULL) { BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED); ERR_add_error_data(2,"host=",c->param_hostname); goto exit_loop; } c->state=BIO_CONN_S_GET_IP; break; case BIO_CONN_S_GET_IP: if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0) goto exit_loop; c->state=BIO_CONN_S_GET_PORT; break; case BIO_CONN_S_GET_PORT: if (c->param_port == NULL) { /* abort(); */ goto exit_loop; } else if (BIO_get_port(c->param_port,&c->port) <= 0) goto exit_loop; c->state=BIO_CONN_S_CREATE_SOCKET; break; case BIO_CONN_S_CREATE_SOCKET: /* now setup address */ memset((char *)&c->them,0,sizeof(c->them)); c->them.sin_family=AF_INET; c->them.sin_port=htons((unsigned short)c->port); l=(unsigned long) ((unsigned long)c->ip[0]<<24L)| ((unsigned long)c->ip[1]<<16L)| ((unsigned long)c->ip[2]<< 8L)| ((unsigned long)c->ip[3]); c->them.sin_addr.s_addr=htonl(l); c->state=BIO_CONN_S_CREATE_SOCKET; ret=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL); if (ret == INVALID_SOCKET) { SYSerr(SYS_F_SOCKET,get_last_socket_error()); ERR_add_error_data(4,"host=",c->param_hostname, ":",c->param_port); BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET); goto exit_loop; } b->num=ret; c->state=BIO_CONN_S_NBIO; break; case BIO_CONN_S_NBIO: if (c->nbio) { if (!BIO_socket_nbio(b->num,1)) { BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO); ERR_add_error_data(4,"host=", c->param_hostname, ":",c->param_port); goto exit_loop; } } c->state=BIO_CONN_S_CONNECT; #if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) i=1; i=setsockopt(b->num,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); if (i < 0) { SYSerr(SYS_F_SOCKET,get_last_socket_error()); ERR_add_error_data(4,"host=",c->param_hostname, ":",c->param_port); BIOerr(BIO_F_CONN_STATE,BIO_R_KEEPALIVE); goto exit_loop; } #endif break; case BIO_CONN_S_CONNECT: BIO_clear_retry_flags(b); ret=connect(b->num, (struct sockaddr *)&c->them, sizeof(c->them)); b->retry_reason=0; if (ret < 0) { if (BIO_sock_should_retry(ret)) { BIO_set_retry_special(b); c->state=BIO_CONN_S_BLOCKED_CONNECT; b->retry_reason=BIO_RR_CONNECT; } else { SYSerr(SYS_F_CONNECT,get_last_socket_error()); ERR_add_error_data(4,"host=", c->param_hostname, ":",c->param_port); BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR); } goto exit_loop; } else c->state=BIO_CONN_S_OK; break; case BIO_CONN_S_BLOCKED_CONNECT: i=BIO_sock_error(b->num); if (i) { BIO_clear_retry_flags(b); SYSerr(SYS_F_CONNECT,i); ERR_add_error_data(4,"host=", c->param_hostname, ":",c->param_port); BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR); ret=0; goto exit_loop; } else c->state=BIO_CONN_S_OK; break; case BIO_CONN_S_OK: ret=1; goto exit_loop; default: /* abort(); */ goto exit_loop; } if (cb != NULL) { if (!(ret=cb((BIO *)b,c->state,ret))) goto end; } } /* Loop does not exit */ exit_loop: if (cb != NULL) ret=cb((BIO *)b,c->state,ret); end: return(ret); }