/*********************************************************************** * MAIN - main processing area for client * real name depends on MONOLITH */ int s_time_main(int argc, char **argv) { double totalTime = 0.0; int nConn = 0; SSL *scon = NULL; long finishtime = 0; int ret = 1, i; char buf[1024 * 8]; int ver; if (single_execution) { if (pledge("stdio inet rpath", NULL) == -1) { perror("pledge"); exit(1); } } s_time_meth = SSLv23_client_method(); verify_depth = 0; memset(&s_time_config, 0, sizeof(s_time_config)); s_time_config.host = SSL_CONNECT_NAME; s_time_config.maxtime = SECONDS; s_time_config.perform = 3; s_time_config.verify = SSL_VERIFY_NONE; s_time_config.verify_depth = -1; if (options_parse(argc, argv, s_time_options, NULL, NULL) != 0) { s_time_usage(); goto end; } if (s_time_config.verify_depth >= 0) { s_time_config.verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; verify_depth = s_time_config.verify_depth; BIO_printf(bio_err, "verify depth is %d\n", verify_depth); } if (s_time_config.www_path != NULL && strlen(s_time_config.www_path) > MYBUFSIZ - 100) { BIO_printf(bio_err, "-www option too long\n"); goto end; } if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL) return (1); SSL_CTX_set_quiet_shutdown(tm_ctx, 1); if (s_time_config.bugs) SSL_CTX_set_options(tm_ctx, SSL_OP_ALL); if (s_time_config.cipher != NULL) { if (!SSL_CTX_set_cipher_list(tm_ctx, s_time_config.cipher)) { BIO_printf(bio_err, "error setting cipher list\n"); ERR_print_errors(bio_err); goto end; } } SSL_CTX_set_verify(tm_ctx, s_time_config.verify, NULL); if (!set_cert_stuff(tm_ctx, s_time_config.certfile, s_time_config.keyfile)) goto end; if ((!SSL_CTX_load_verify_locations(tm_ctx, s_time_config.CAfile, s_time_config.CApath)) || (!SSL_CTX_set_default_verify_paths(tm_ctx))) { /* * BIO_printf(bio_err,"error setting default verify * locations\n"); */ ERR_print_errors(bio_err); /* goto end; */ } if (!(s_time_config.perform & 1)) goto next; printf("Collecting connection statistics for %d seconds\n", s_time_config.maxtime); /* Loop and time how long it takes to make connections */ bytes_read = 0; finishtime = (long) time(NULL) + s_time_config.maxtime; tm_Time_F(START); for (;;) { if (finishtime < (long) time(NULL)) break; if ((scon = doConnection(NULL)) == NULL) goto end; if (s_time_config.www_path != NULL) { int retval = snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path); if ((size_t)retval >= sizeof buf) { fprintf(stderr, "URL too long\n"); goto end; } SSL_write(scon, buf, strlen(buf)); while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } if (s_time_config.no_shutdown) SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); else SSL_shutdown(scon); shutdown(SSL_get_fd(scon), SHUT_RDWR); close(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) ver = 'r'; else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else if (ver == SSL2_VERSION) ver = '2'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); SSL_free(scon); scon = NULL; } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ i = (int) ((long) time(NULL) - finishtime + s_time_config.maxtime); printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read); printf("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + s_time_config.maxtime, bytes_read / nConn); /* * Now loop and time connections using the same session id over and * over */ next: if (!(s_time_config.perform & 2)) goto end; printf("\n\nNow timing with session id reuse.\n"); /* Get an SSL object so we can reuse the session id */ if ((scon = doConnection(NULL)) == NULL) { fprintf(stderr, "Unable to get connection\n"); goto end; } if (s_time_config.www_path != NULL) { int retval = snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path); if ((size_t)retval >= sizeof buf) { fprintf(stderr, "URL too long\n"); goto end; } SSL_write(scon, buf, strlen(buf)); while (SSL_read(scon, buf, sizeof(buf)) > 0); } if (s_time_config.no_shutdown) SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); else SSL_shutdown(scon); shutdown(SSL_get_fd(scon), SHUT_RDWR); close(SSL_get_fd(scon)); nConn = 0; totalTime = 0.0; finishtime = (long) time(NULL) + s_time_config.maxtime; printf("starting\n"); bytes_read = 0; tm_Time_F(START); for (;;) { if (finishtime < (long) time(NULL)) break; if ((doConnection(scon)) == NULL) goto end; if (s_time_config.www_path) { int retval = snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path); if ((size_t)retval >= sizeof buf) { fprintf(stderr, "URL too long\n"); goto end; } SSL_write(scon, buf, strlen(buf)); while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } if (s_time_config.no_shutdown) SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); else SSL_shutdown(scon); shutdown(SSL_get_fd(scon), SHUT_RDWR); close(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) ver = 'r'; else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else if (ver == SSL2_VERSION) ver = '2'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read); printf("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + s_time_config.maxtime, bytes_read / nConn); ret = 0; end: if (scon != NULL) SSL_free(scon); if (tm_ctx != NULL) { SSL_CTX_free(tm_ctx); tm_ctx = NULL; } return (ret); }
/* * Retrieve URL, via the proxy in $proxyvar if necessary. * Modifies the string argument given. * Returns -1 on failure, 0 on success */ static int url_get(const char *origline, const char *proxyenv, const char *outfile) { char pbuf[NI_MAXSERV], hbuf[NI_MAXHOST], *cp, *portnum, *path, ststr[4]; char *hosttail, *cause = "unknown", *newline, *host, *port, *buf = NULL; int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1; struct addrinfo hints, *res0, *res; const char * volatile savefile; char * volatile proxyurl = NULL; char *cookie = NULL; volatile int s = -1, out; volatile sig_t oldintr; FILE *fin = NULL; off_t hashbytes; const char *errstr; size_t len, wlen; #ifndef SMALL char *sslpath = NULL, *sslhost = NULL; int ishttpsurl = 0; SSL_CTX *ssl_ctx = NULL; #endif /* !SMALL */ SSL *ssl = NULL; int status; newline = strdup(origline); if (newline == NULL) errx(1, "Can't allocate memory to parse URL"); if (strncasecmp(newline, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) host = newline + sizeof(HTTP_URL) - 1; else if (strncasecmp(newline, FTP_URL, sizeof(FTP_URL) - 1) == 0) { host = newline + sizeof(FTP_URL) - 1; isftpurl = 1; } else if (strncasecmp(newline, FILE_URL, sizeof(FILE_URL) - 1) == 0) { host = newline + sizeof(FILE_URL) - 1; isfileurl = 1; #ifndef SMALL } else if (strncasecmp(newline, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0) { host = newline + sizeof(HTTPS_URL) - 1; ishttpsurl = 1; #endif /* !SMALL */ } else errx(1, "url_get: Invalid URL '%s'", newline); if (isfileurl) { path = host; } else { path = strchr(host, '/'); /* find path */ if (EMPTYSTRING(path)) { if (isftpurl) goto noftpautologin; warnx("Invalid URL (no `/' after host): %s", origline); goto cleanup_url_get; } *path++ = '\0'; if (EMPTYSTRING(path)) { if (isftpurl) goto noftpautologin; warnx("Invalid URL (no file after host): %s", origline); goto cleanup_url_get; } } if (outfile) savefile = outfile; else savefile = basename(path); #ifndef SMALL if (resume && (strcmp(savefile, "-") == 0)) { warnx("can't append to stdout"); goto cleanup_url_get; } #endif /* !SMALL */ if (EMPTYSTRING(savefile)) { if (isftpurl) goto noftpautologin; warnx("Invalid URL (no file after directory): %s", origline); goto cleanup_url_get; } if (!isfileurl && proxyenv != NULL) { /* use proxy */ #ifndef SMALL if (ishttpsurl) { sslpath = strdup(path); sslhost = strdup(host); if (! sslpath || ! sslhost) errx(1, "Can't allocate memory for https path/host."); } #endif /* !SMALL */ proxyurl = strdup(proxyenv); if (proxyurl == NULL) errx(1, "Can't allocate memory for proxy URL."); if (strncasecmp(proxyurl, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) host = proxyurl + sizeof(HTTP_URL) - 1; else if (strncasecmp(proxyurl, FTP_URL, sizeof(FTP_URL) - 1) == 0) host = proxyurl + sizeof(FTP_URL) - 1; else { warnx("Malformed proxy URL: %s", proxyenv); goto cleanup_url_get; } if (EMPTYSTRING(host)) { warnx("Malformed proxy URL: %s", proxyenv); goto cleanup_url_get; } *--path = '/'; /* add / back to real path */ path = strchr(host, '/'); /* remove trailing / on host */ if (!EMPTYSTRING(path)) *path++ = '\0'; /* i guess this ++ is useless */ path = strchr(host, '@'); /* look for credentials in proxy */ if (!EMPTYSTRING(path)) { *path++ = '\0'; cookie = strchr(host, ':'); if (EMPTYSTRING(cookie)) { warnx("Malformed proxy URL: %s", proxyenv); goto cleanup_url_get; } cookie = malloc(COOKIE_MAX_LEN); b64_ntop(host, strlen(host), cookie, COOKIE_MAX_LEN); /* * This removes the password from proxyenv, * filling with stars */ for (host = strchr(proxyenv + 5, ':'); *host != '@'; host++) *host = '*'; host = path; } path = newline; } if (isfileurl) { struct stat st; s = open(path, O_RDONLY); if (s == -1) { warn("Can't open file %s", path); goto cleanup_url_get; } if (fstat(s, &st) == -1) filesize = -1; else filesize = st.st_size; /* Open the output file. */ if (strcmp(savefile, "-") != 0) { #ifndef SMALL if (resume) out = open(savefile, O_APPEND | O_WRONLY); else #endif /* !SMALL */ out = open(savefile, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (out < 0) { warn("Can't open %s", savefile); goto cleanup_url_get; } } else out = fileno(stdout); #ifndef SMALL if (resume) { if (fstat(out, &st) == -1) { warn("Can't fstat %s", savefile); goto cleanup_url_get; } if (lseek(s, st.st_size, SEEK_SET) == -1) { warn("Can't lseek %s", path); goto cleanup_url_get; } restart_point = st.st_size; } #endif /* !SMALL */ /* Trap signals */ oldintr = NULL; if (setjmp(httpabort)) { if (oldintr) (void)signal(SIGINT, oldintr); goto cleanup_url_get; } oldintr = signal(SIGINT, abortfile); bytes = 0; hashbytes = mark; progressmeter(-1); if ((buf = malloc(4096)) == NULL) errx(1, "Can't allocate memory for transfer buffer"); /* Finally, suck down the file. */ i = 0; while ((len = read(s, buf, 4096)) > 0) { bytes += len; for (cp = buf; len > 0; len -= i, cp += i) { if ((i = write(out, cp, len)) == -1) { warn("Writing %s", savefile); goto cleanup_url_get; } else if (i == 0) break; } if (hash && !progress) { while (bytes >= hashbytes) { (void)putc('#', ttyout); hashbytes += mark; } (void)fflush(ttyout); } } if (hash && !progress && bytes > 0) { if (bytes < mark) (void)putc('#', ttyout); (void)putc('\n', ttyout); (void)fflush(ttyout); } if (len != 0) { warn("Reading from file"); goto cleanup_url_get; } progressmeter(1); if (verbose) fputs("Successfully retrieved file.\n", ttyout); (void)signal(SIGINT, oldintr); rval = 0; goto cleanup_url_get; } if (*host == '[' && (hosttail = strrchr(host, ']')) != NULL && (hosttail[1] == '\0' || hosttail[1] == ':')) { host++; *hosttail++ = '\0'; } else hosttail = host; portnum = strrchr(hosttail, ':'); /* find portnum */ if (portnum != NULL) *portnum++ = '\0'; #ifndef SMALL if (debug) fprintf(ttyout, "host %s, port %s, path %s, save as %s.\n", host, portnum, path, savefile); #endif /* !SMALL */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; #ifndef SMALL port = portnum ? portnum : (ishttpsurl ? httpsport : httpport); #else /* !SMALL */ port = portnum ? portnum : httpport; #endif /* !SMALL */ error = getaddrinfo(host, port, &hints, &res0); /* * If the services file is corrupt/missing, fall back * on our hard-coded defines. */ if (error == EAI_SERVICE && port == httpport) { snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT); error = getaddrinfo(host, pbuf, &hints, &res0); #ifndef SMALL } else if (error == EAI_SERVICE && port == httpsport) { snprintf(pbuf, sizeof(pbuf), "%d", HTTPS_PORT); error = getaddrinfo(host, pbuf, &hints, &res0); #endif /* !SMALL */ } if (error) { warnx("%s: %s", gai_strerror(error), host); goto cleanup_url_get; } s = -1; for (res = res0; res; res = res->ai_next) { if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) strlcpy(hbuf, "(unknown)", sizeof(hbuf)); if (verbose) fprintf(ttyout, "Trying %s...\n", hbuf); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { cause = "socket"; continue; } again: if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { int save_errno; if (errno == EINTR) goto again; save_errno = errno; close(s); errno = save_errno; s = -1; cause = "connect"; continue; } /* get port in numeric */ if (getnameinfo(res->ai_addr, res->ai_addrlen, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) == 0) port = pbuf; else port = NULL; #ifndef SMALL if (proxyenv && sslhost) proxy_connect(s, sslhost); #endif /* !SMALL */ break; } freeaddrinfo(res0); if (s < 0) { warn("%s", cause); goto cleanup_url_get; } #ifndef SMALL if (ishttpsurl) { if (proxyenv && sslpath) { ishttpsurl = 0; proxyurl = NULL; path = sslpath; } SSL_library_init(); SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); ssl_ctx = SSL_CTX_new(SSLv23_client_method()); ssl = SSL_new(ssl_ctx); if (ssl == NULL || ssl_ctx == NULL) { ERR_print_errors_fp(ttyout); goto cleanup_url_get; } if (SSL_set_fd(ssl, s) == 0) { ERR_print_errors_fp(ttyout); goto cleanup_url_get; } if (SSL_connect(ssl) <= 0) { ERR_print_errors_fp(ttyout); goto cleanup_url_get; } } else { fin = fdopen(s, "r+"); } #else /* !SMALL */ fin = fdopen(s, "r+"); #endif /* !SMALL */ if (verbose) fprintf(ttyout, "Requesting %s", origline); /* * Construct and send the request. Proxy requests don't want leading /. */ #ifndef SMALL cookie_get(host, path, ishttpsurl, &buf); #endif /* !SMALL */ if (proxyurl) { if (verbose) fprintf(ttyout, " (via %s)\n", proxyenv); /* * Host: directive must use the destination host address for * the original URI (path). We do not attach it at this moment. */ if (cookie) ftp_printf(fin, ssl, "GET %s HTTP/1.0\r\n" "Proxy-Authorization: Basic %s%s\r\n%s\r\n\r\n", path, cookie, buf ? buf : "", HTTP_USER_AGENT); else ftp_printf(fin, ssl, "GET %s HTTP/1.0\r\n%s%s\r\n\r\n", path, buf ? buf : "", HTTP_USER_AGENT); } else { ftp_printf(fin, ssl, "GET /%s %s\r\nHost: ", path, #ifndef SMALL resume ? "HTTP/1.1" : #endif /* !SMALL */ "HTTP/1.0"); if (strchr(host, ':')) { char *h, *p; /* * strip off scoped address portion, since it's * local to node */ h = strdup(host); if (h == NULL) errx(1, "Can't allocate memory."); if ((p = strchr(h, '%')) != NULL) *p = '\0'; ftp_printf(fin, ssl, "[%s]", h); free(h); } else ftp_printf(fin, ssl, "%s", host); /* * Send port number only if it's specified and does not equal * 80. Some broken HTTP servers get confused if you explicitly * send them the port number. */ #ifndef SMALL if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0) ftp_printf(fin, ssl, ":%s", port); if (resume) { int ret; struct stat stbuf; ret = stat(savefile, &stbuf); if (ret < 0) { if (verbose) fprintf(ttyout, "\n"); warn("Can't open %s", savefile); goto cleanup_url_get; } restart_point = stbuf.st_size; ftp_printf(fin, ssl, "\r\nRange: bytes=%lld-", (long long)restart_point); } #else /* !SMALL */ if (port && strcmp(port, "80") != 0) ftp_printf(fin, ssl, ":%s", port); #endif /* !SMALL */ ftp_printf(fin, ssl, "\r\n%s%s\r\n\r\n", buf ? buf : "", HTTP_USER_AGENT); if (verbose) fprintf(ttyout, "\n"); } #ifndef SMALL free(buf); #endif /* !SMALL */ buf = NULL; if (fin != NULL && fflush(fin) == EOF) { warn("Writing HTTP request"); goto cleanup_url_get; } if ((buf = ftp_readline(fin, ssl, &len)) == NULL) { warn("Receiving HTTP reply"); goto cleanup_url_get; } while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n')) buf[--len] = '\0'; #ifndef SMALL if (debug) fprintf(ttyout, "received '%s'\n", buf); #endif /* !SMALL */ cp = strchr(buf, ' '); if (cp == NULL) goto improper; else cp++; strlcpy(ststr, cp, sizeof(ststr)); status = strtonum(ststr, 200, 416, &errstr); if (errstr) { warnx("Error retrieving file: %s", cp); goto cleanup_url_get; } switch (status) { case 200: /* OK */ #ifndef SMALL case 206: /* Partial Content */ break; #endif /* !SMALL */ case 301: /* Moved Permanently */ case 302: /* Found */ case 303: /* See Other */ case 307: /* Temporary Redirect */ isredirect++; if (redirect_loop++ > 10) { warnx("Too many redirections requested"); goto cleanup_url_get; } break; #ifndef SMALL case 416: /* Requested Range Not Satisfiable */ warnx("File is already fully retrieved."); goto cleanup_url_get; #endif /* !SMALL */ default: warnx("Error retrieving file: %s", cp); goto cleanup_url_get; } /* * Read the rest of the header. */ free(buf); filesize = -1; for (;;) { if ((buf = ftp_readline(fin, ssl, &len)) == NULL) { warn("Receiving HTTP reply"); goto cleanup_url_get; } while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n')) buf[--len] = '\0'; if (len == 0) break; #ifndef SMALL if (debug) fprintf(ttyout, "received '%s'\n", buf); #endif /* !SMALL */ /* Look for some headers */ cp = buf; #define CONTENTLEN "Content-Length: " if (strncasecmp(cp, CONTENTLEN, sizeof(CONTENTLEN) - 1) == 0) { cp += sizeof(CONTENTLEN) - 1; filesize = strtonum(cp, 0, LLONG_MAX, &errstr); if (errstr != NULL) goto improper; #ifndef SMALL if (resume) filesize += restart_point; #endif /* !SMALL */ #define LOCATION "Location: " } else if (isredirect && strncasecmp(cp, LOCATION, sizeof(LOCATION) - 1) == 0) { cp += sizeof(LOCATION) - 1; if (verbose) fprintf(ttyout, "Redirected to %s\n", cp); if (fin != NULL) fclose(fin); else if (s != -1) close(s); free(proxyurl); free(newline); rval = url_get(cp, proxyenv, outfile); free(buf); return (rval); } } /* Open the output file. */ if (strcmp(savefile, "-") != 0) { #ifndef SMALL if (resume) out = open(savefile, O_APPEND | O_WRONLY); else #endif /* !SMALL */ out = open(savefile, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (out < 0) { warn("Can't open %s", savefile); goto cleanup_url_get; } } else out = fileno(stdout); /* Trap signals */ oldintr = NULL; if (setjmp(httpabort)) { if (oldintr) (void)signal(SIGINT, oldintr); goto cleanup_url_get; } oldintr = signal(SIGINT, aborthttp); bytes = 0; hashbytes = mark; progressmeter(-1); free(buf); /* Finally, suck down the file. */ if ((buf = malloc(4096)) == NULL) errx(1, "Can't allocate memory for transfer buffer"); i = 0; len = 1; while (len > 0) { len = ftp_read(fin, ssl, buf, 4096); bytes += len; for (cp = buf, wlen = len; wlen > 0; wlen -= i, cp += i) { if ((i = write(out, cp, wlen)) == -1) { warn("Writing %s", savefile); goto cleanup_url_get; } else if (i == 0) break; } if (hash && !progress) { while (bytes >= hashbytes) { (void)putc('#', ttyout); hashbytes += mark; } (void)fflush(ttyout); } } if (hash && !progress && bytes > 0) { if (bytes < mark) (void)putc('#', ttyout); (void)putc('\n', ttyout); (void)fflush(ttyout); } if (len != 0) { warn("Reading from socket"); goto cleanup_url_get; } progressmeter(1); if ( #ifndef SMALL !resume && #endif /* !SMALL */ filesize != -1 && len == 0 && bytes != filesize) { if (verbose) fputs("Read short file.\n", ttyout); goto cleanup_url_get; } if (verbose) fputs("Successfully retrieved file.\n", ttyout); (void)signal(SIGINT, oldintr); rval = 0; goto cleanup_url_get; noftpautologin: warnx( "Auto-login using ftp URLs isn't supported when using $ftp_proxy"); goto cleanup_url_get; improper: warnx("Improper response from %s", host); cleanup_url_get: #ifndef SMALL if (ssl) { SSL_shutdown(ssl); SSL_free(ssl); } #endif /* !SMALL */ if (fin != NULL) fclose(fin); else if (s != -1) close(s); free(buf); free(proxyurl); free(newline); return (rval); }
void *thread_main (void *arg) { int err, buflen, read; int sd; SSL_CTX *ctx = (SSL_CTX *) arg; struct sockaddr_in dest_sin; int sock; #ifdef _WIN32 PHOSTENT phe; WORD wVersionRequested; WSADATA wsaData; #endif /* */ SSL *ssl; X509 *server_cert; char *str; char buf[1024]; SSL_METHOD *meth; FILE *fp; #ifdef _WIN32 wVersionRequested = MAKEWORD (2, 2); err = WSAStartup (wVersionRequested, &wsaData); if (err != 0) { printf ("WSAStartup err\n"); return -1; } #endif /* */ //首先建立连接 sock = socket (AF_INET, SOCK_STREAM, 0); dest_sin.sin_family = AF_INET; dest_sin.sin_addr.s_addr = inet_addr ("127.0.0.1"); dest_sin.sin_port = htons (8888); again:err = connect (sock, (struct sockaddr_in *) &dest_sin, sizeof (dest_sin)); if (err < 0) { sleep (1); goto again; } //安全连接要求在连接建立后进行握手 ssl = SSL_new (ctx); if (ssl == NULL) { printf ("ss new err\n"); return; } SSL_set_fd (ssl, sock); //请求SSL连接 err = SSL_connect (ssl); if (err < 0) { printf ("SSL_connect err\n"); return; } printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); // server_cert = SSL_get_peer_certificate (ssl); printf ("Server certificate:\n"); //获得服务端证书subject并转变成字符型,以便进行打印 str = X509_NAME_oneline (X509_get_subject_name (server_cert), 0, 0); printf ("\t subject: %s\n", str); OPENSSL_free (str); //获得客户端证书issuer并转变成字符型,以便进行打印 str = X509_NAME_oneline (X509_get_issuer_name (server_cert), 0, 0); printf ("\t issuer: %s\n", str); OPENSSL_free (str); X509_free (server_cert); //进行安全会话 err = SSL_write (ssl, "Hello World!", strlen ("Hello World!")); if (err < 0) { printf ("ssl write err\n"); return; } #if 0 memset (buf, 0, ONE_BUF_SIZE); err = SSL_read (ssl, buf, sizeof (buf) - 1); if (err < 0) { printf ("ssl read err\n"); return; } buf[err] = '\0'; printf ("Got %d chars:'%s'\n", err, buf); #endif /* */ SSL_shutdown (ssl); SSL_free (ssl); close (sock); /* send SSL/TLS close_notify */ }
void hgd_service_client(int cli_fd, struct sockaddr_in *cli_addr) { struct hgd_session sess; char *recv_line; uint8_t exit, ssl_dead = 0; sess.cli_str = hgd_identify_client(cli_addr); sess.sock_fd = cli_fd; sess.cli_addr = cli_addr; sess.user = NULL; sess.ssl = NULL; if (sess.cli_str == NULL) xasprintf(&sess.cli_str, "unknown"); /* shouldn't happen */ DPRINTF(HGD_D_INFO, "Client connection: '%s'", sess.cli_str); /* oh hai */ hgd_sock_send_line(cli_fd, sess.ssl, HGD_GREET); /* main command recieve loop */ do { recv_line = hgd_sock_recv_line(sess.sock_fd, sess.ssl); exit = hgd_parse_line(&sess, recv_line); free(recv_line); if (num_bad_commands >= HGD_MAX_BAD_COMMANDS) { DPRINTF(HGD_D_WARN,"Client abused server, " "kicking '%s'", sess.cli_str); /* laters */ hgd_sock_send_line(cli_fd, sess.ssl, HGD_BYE_KICK); close(sess.sock_fd); exit_ok = 1; hgd_exit_nicely(); } } while (!exit && !dying && !restarting); /* * client service procs should not respawn as liesteners, * that would suck. This may need tweaking later, as the exit * message may be misinterpreted (?) Handling HUP is hard. */ if (restarting) { dying = 1; restarting = 0; exit_ok = 1; } /* laters */ hgd_sock_send_line(cli_fd, sess.ssl, HGD_BYE); /* free up the hgd_session members */ if (sess.cli_str != NULL) free(sess.cli_str); if (sess.ssl != NULL) { while (!ssl_dead) ssl_dead = SSL_shutdown(sess.ssl); SSL_free(sess.ssl); } if (sess.user) { if (sess.user->name) free(sess.user->name); free(sess.user); } }
void swSSL_close(swConnection *conn) { SSL_shutdown(conn->ssl); SSL_free(conn->ssl); }
BOOL cg_socket_close(CgSocket *sock) { cg_log_debug_l4("Entering...\n"); if (cg_socket_isbound(sock) == FALSE) return TRUE; #if defined(CG_USE_OPENSSL) if (cg_socket_isssl(sock) == TRUE) { if (sock->ctx) { SSL_shutdown(sock->ssl); SSL_free(sock->ssl); sock->ssl = NULL; } if (sock->ctx) { SSL_CTX_free(sock->ctx); sock->ctx = NULL; } } #endif #if (defined(WIN32) || defined(__CYGWIN__)) && !defined(ITRON) #if !defined(WINCE) WSAAsyncSelect(sock->id, NULL, 0, FD_CLOSE); #endif shutdown(sock->id, SD_BOTH ); #if defined WINCE { int nRet = 1; char achDiscard[256]; while (nRet && (nRet != SOCKET_ERROR)){ if (nRet>0) { achDiscard[nRet]=(char)0; #if defined DEBUG_SOCKET printf("DUMMY READ WHILE CLOSING SOCKET \n%s\n",achDiscard); #endif } nRet = recv(sock->id,achDiscard,128,0); } } #endif closesocket(sock->id); #if !defined(__CYGWIN__) && !defined(__MINGW32__) sock->id = INVALID_SOCKET; #else sock->id = -1; #endif #else #if defined(BTRON) || (defined(TENGINE) && !defined(CG_TENGINE_NET_KASAGO)) so_shutdown(sock->id, 2); so_close(sock->id); #elif defined(TENGINE) && defined(CG_TENGINE_NET_KASAGO) ka_tfClose(sock->id); #elif defined(ITRON) if (cg_socket_issocketstream(sock) == TRUE) { tcp_can_cep(sock->id, TFN_TCP_ALL); tcp_sht_cep(sock->id); tcp_del_cep(sock->id); tcp_cls_cep(sock->id, TMO_FEVR); tcp_del_rep(sock->id); } else { udp_can_cep(sock->id, TFN_UDP_ALL); udp_del_cep(sock->id); } #else int flag = fcntl(sock->id, F_GETFL, 0); if (0 <= flag) fcntl(sock->id, F_SETFL, flag | O_NONBLOCK); shutdown(sock->id, 2); close(sock->id); #endif sock->id = -1; #endif cg_socket_setaddress(sock, ""); cg_socket_setport(sock, -1); return TRUE; cg_log_debug_l4("Leaving...\n"); }
void https_service_conn(int conn_sock, SSL_CTX *ctx) { char buf[MAX_BUF_LENGTH]; int count, retv; struct message *msg; /* openssl library definitions */ SSL* ssl; ssl = SSL_new(ctx); if (ssl == NULL) { perror("cannot create SSL object!"); return; } SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); SSL_set_fd(ssl, conn_sock); SSL_set_accept_state(ssl); retv = SSL_accept(ssl); if (retv < 0) goto ERROR; count = SSL_read(ssl, buf, MAX_BUF_LENGTH-1); if (count < 0) goto ERROR; buf[count] = '\0'; printf(buf); if (!strncmp(buf, "GET", 3)) { char url[256]; strtok(buf, " "); strcpy(url, https_s.dir); strcat(url, strtok(NULL, " ")); if (strcmp(url, "index.html")) { write_url_ssl(ssl, buf, url); } else if (strcmp(url, "guest_panel.html")) { if (check_privileges()) { write_url_ssl(ssl, buf, url); } else { write_404_ssl(ssl, buf, "<html><body>You don't have access! Go away!</body></html>"); } } else if (strcmp(url, "admin_panel.html")) { if (check_privileges() == ADMIN_PRIV) { write_url_ssl(ssl, buf, url); } else { write_404_ssl(ssl, buf, "<html><body>You don't have access! Go away!</body></html>"); } } } if (!strncmp(buf, "POST", 4)) { int i; char *tmp; char *password; char *username; int admin_login = 1; int guest_login = 1; char *ble = buf; if ((tmp = strstr(buf, "username")) != NULL) { if (strcmp("username", strtok(tmp, "=&"))) { admin_login = 0; guest_login = 0; } username = strtok(NULL, "=&"); printf("user: %s\n", username); if (strcmp(username, https_d.admin_username)) admin_login = 0; if (strcmp(username, https_d.guest_username)) guest_login = 0; if (strcmp("password", strtok(NULL, "=&"))) { admin_login = 0; guest_login = 0; } password = strtok(NULL, "=&"); printf("pass: %s\n", password); if (strcmp(password, https_d.admin_password)) admin_login = 0; if (strcmp(password, https_d.guest_password)) guest_login = 0; if (admin_login) { /* * save session id with appropriate flag */ save_session(ssl, ADMIN_PRIV); write_url_ssl(ssl, buf, "admin_login.html"); } if (guest_login) { /* * save session id with appropriate flag */ save_session(ssl, GUEST_PRIV); write_url_ssl(ssl, buf, "guest_login.html"); } if (!admin_login && !guest_login) { write_404_ssl(ssl, buf, "<html><body>Logging has failed! Go away!</body></html>"); } //printf(buf); } else if ((tmp = strstr(buf, "killall")) != NULL) { /* killal has been issued */ if (check_privileges(ssl) == ADMIN_PRIV) { system("killall.sh"); } else { write_404_ssl(ssl, buf, "<html><body>You cannot do that!Go away!</body></html>"); } } else if ((tmp = strstr(buf, "poweroff")) != NULL) { if (check_privileges(ssl) == ADMIN_PRIV) { system("poweroff.sh"); } else { write_404_ssl(ssl, buf, "<html><body>You cannot do that!Go away!</body></html>"); } } else if ((tmp = strstr(buf, "something")) != NULL) { if (check_privileges(ssl) == ADMIN_PRIV) { system("something.sh"); } else { write_404_ssl(ssl, buf, "<html><body>You cannot do that!Go away!</body></html>"); } } } SSL_shutdown(ssl); SSL_free(ssl); close(conn_sock); exit(EXIT_SUCCESS); ERROR: SSL_shutdown(ssl); SSL_free(ssl); close(conn_sock); exit(EXIT_FAILURE); }
int lws_server_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd) { struct libwebsocket *new_wsi; int accept_fd; socklen_t clilen; struct sockaddr_in cli_addr; int n; int len; #ifdef LWS_OPENSSL_SUPPORT int m; #ifndef USE_CYASSL BIO *bio; #endif #endif switch (wsi->mode) { case LWS_CONNMODE_HTTP_SERVING: case LWS_CONNMODE_HTTP_SERVING_ACCEPTED: /* handle http headers coming in */ /* pending truncated sends have uber priority */ if (wsi->truncated_send_malloc) { if (pollfd->revents & LWS_POLLOUT) lws_issue_raw(wsi, wsi->truncated_send_malloc + wsi->truncated_send_offset, wsi->truncated_send_len); /* * we can't afford to allow input processing send * something new, so spin around he event loop until * he doesn't have any partials */ break; } /* any incoming data ready? */ if (pollfd->revents & LWS_POLLIN) { len = lws_ssl_capable_read(wsi, context->service_buffer, sizeof(context->service_buffer)); switch (len) { case 0: lwsl_info("lws_server_skt_srv: read 0 len\n"); /* lwsl_info(" state=%d\n", wsi->state); */ if (!wsi->hdr_parsing_completed) free(wsi->u.hdr.ah); /* fallthru */ case LWS_SSL_CAPABLE_ERROR: libwebsocket_close_and_free_session( context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 0; case LWS_SSL_CAPABLE_MORE_SERVICE: break; } /* hm this may want to send (via HTTP callback for example) */ n = libwebsocket_read(context, wsi, context->service_buffer, len); if (n < 0) /* we closed wsi */ return 0; /* hum he may have used up the writability above */ break; } /* this handles POLLOUT for http serving fragments */ if (!(pollfd->revents & LWS_POLLOUT)) break; /* one shot */ if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) goto fail; #ifdef LWS_USE_LIBEV if (LWS_LIBEV_ENABLED(context)) ev_io_stop(context->io_loop, (struct ev_io *)&wsi->w_write); #endif /* LWS_USE_LIBEV */ if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) { n = user_callback_handle_rxflow( wsi->protocol->callback, wsi->protocol->owning_server, wsi, LWS_CALLBACK_HTTP_WRITEABLE, wsi->user_space, NULL, 0); if (n < 0) libwebsocket_close_and_free_session( context, wsi, LWS_CLOSE_STATUS_NOSTATUS); break; } /* nonzero for completion or error */ if (libwebsockets_serve_http_file_fragment(context, wsi)) libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); break; case LWS_CONNMODE_SERVER_LISTENER: /* pollin means a client has connected to us then */ if (!(pollfd->revents & LWS_POLLIN)) break; /* listen socket got an unencrypted connection... */ clilen = sizeof(cli_addr); lws_latency_pre(context, wsi); accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr, &clilen); lws_latency(context, wsi, "unencrypted accept LWS_CONNMODE_SERVER_LISTENER", accept_fd, accept_fd >= 0); if (accept_fd < 0) { if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK) { lwsl_debug("accept asks to try again\n"); break; } lwsl_warn("ERROR on accept: %s\n", strerror(LWS_ERRNO)); break; } lws_plat_set_socket_options(context, accept_fd); /* * look at who we connected to and give user code a chance * to reject based on client IP. There's no protocol selected * yet so we issue this to protocols[0] */ if ((context->protocols[0].callback)(context, wsi, LWS_CALLBACK_FILTER_NETWORK_CONNECTION, NULL, (void *)(long)accept_fd, 0)) { lwsl_debug("Callback denied network connection\n"); compatible_close(accept_fd); break; } new_wsi = libwebsocket_create_new_server_wsi(context); if (new_wsi == NULL) { compatible_close(accept_fd); break; } new_wsi->sock = accept_fd; /* the transport is accepted... give him time to negotiate */ libwebsocket_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, AWAITING_TIMEOUT); /* * A new connection was accepted. Give the user a chance to * set properties of the newly created wsi. There's no protocol * selected yet so we issue this to protocols[0] */ (context->protocols[0].callback)(context, new_wsi, LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0); #ifdef LWS_USE_LIBEV if (LWS_LIBEV_ENABLED(context)) { new_wsi->w_read.context = context; new_wsi->w_write.context = context; /* new_wsi->w_read.wsi = new_wsi; new_wsi->w_write.wsi = new_wsi; */ struct ev_io* w_read = (struct ev_io*)&(new_wsi->w_read); struct ev_io* w_write = (struct ev_io*)&(new_wsi->w_write); ev_io_init(w_read,libwebsocket_accept_cb,accept_fd,EV_READ); ev_io_init(w_write,libwebsocket_accept_cb,accept_fd,EV_WRITE); } #endif /* LWS_USE_LIBEV */ #ifdef LWS_OPENSSL_SUPPORT new_wsi->ssl = NULL; if (!context->use_ssl) { #endif lwsl_debug("accepted new conn port %u on fd=%d\n", ntohs(cli_addr.sin_port), accept_fd); insert_wsi_socket_into_fds(context, new_wsi); break; #ifdef LWS_OPENSSL_SUPPORT } new_wsi->ssl = SSL_new(context->ssl_ctx); if (new_wsi->ssl == NULL) { lwsl_err("SSL_new failed: %s\n", ERR_error_string(SSL_get_error( new_wsi->ssl, 0), NULL)); libwebsockets_decode_ssl_error(); free(new_wsi); compatible_close(accept_fd); break; } SSL_set_ex_data(new_wsi->ssl, openssl_websocket_private_data_index, context); SSL_set_fd(new_wsi->ssl, accept_fd); #ifndef USE_CYASSL SSL_set_mode(new_wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif #ifdef USE_CYASSL CyaSSL_set_using_nonblock(new_wsi->ssl, 1); #else bio = SSL_get_rbio(new_wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(new_wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #endif /* * we are not accepted yet, but we need to enter ourselves * as a live connection. That way we can retry when more * pieces come if we're not sorted yet */ wsi = new_wsi; wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING; insert_wsi_socket_into_fds(context, wsi); libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, AWAITING_TIMEOUT); lwsl_info("inserted SSL accept into fds, trying SSL_accept\n"); /* fallthru */ case LWS_CONNMODE_SSL_ACK_PENDING: if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) goto fail; #ifdef LWS_USE_LIBEV if (LWS_LIBEV_ENABLED(context)) ev_io_stop(context->io_loop, (struct ev_io *)&wsi->w_write); #endif /* LWS_USE_LIBEV */ lws_latency_pre(context, wsi); n = recv(wsi->sock, context->service_buffer, sizeof(context->service_buffer), MSG_PEEK); /* * optionally allow non-SSL connect on SSL listening socket * This is disabled by default, if enabled it goes around any * SSL-level access control (eg, client-side certs) so leave * it disabled unless you know it's not a problem for you */ if (context->allow_non_ssl_on_ssl_port && n >= 1 && context->service_buffer[0] >= ' ') { /* * TLS content-type for Handshake is 0x16 * TLS content-type for ChangeCipherSpec Record is 0x14 * * A non-ssl session will start with the HTTP method in * ASCII. If we see it's not a legit SSL handshake * kill the SSL for this connection and try to handle * as a HTTP connection upgrade directly. */ wsi->use_ssl = 0; SSL_shutdown(wsi->ssl); SSL_free(wsi->ssl); wsi->ssl = NULL; goto accepted; } /* normal SSL connection processing path */ n = SSL_accept(wsi->ssl); lws_latency(context, wsi, "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1); if (n != 1) { m = SSL_get_error(wsi->ssl, n); lwsl_debug("SSL_accept failed %d / %s\n", m, ERR_error_string(m, NULL)); if (m == SSL_ERROR_WANT_READ) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) goto fail; #ifdef LWS_USE_LIBEV if (LWS_LIBEV_ENABLED(context)) ev_io_start(context->io_loop, (struct ev_io *)&wsi->w_read); #endif /* LWS_USE_LIBEV */ lwsl_info("SSL_ERROR_WANT_READ\n"); break; } if (m == SSL_ERROR_WANT_WRITE) { if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) goto fail; #ifdef LWS_USE_LIBEV if (LWS_LIBEV_ENABLED(context)) ev_io_start(context->io_loop, (struct ev_io *)&wsi->w_write); #endif /* LWS_USE_LIBEV */ break; } lwsl_debug("SSL_accept failed skt %u: %s\n", pollfd->fd, ERR_error_string(m, NULL)); libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); break; } accepted: /* OK, we are accepted... give him some time to negotiate */ libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, AWAITING_TIMEOUT); wsi->mode = LWS_CONNMODE_HTTP_SERVING; lwsl_debug("accepted new SSL conn\n"); break; #endif default: break; } return 0; fail: libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; }
void bgcc::SSLEventCallback::DataCallback(EventLoop* el, SOCKET fd, void* arg) { int32_t ret = 0; char* p = NULL; bgcc::Mempool* mempool = bgcc::Mempool::get_instance(); struct SSLEventCallbackArg* callbackArg = (struct SSLEventCallbackArg*)arg; bgcc::ReadItem* pItem = &(Items[fd]); reading_item_t& item = pItem->item; p = item.head_buf; if (S_SIZE_READING == item.state) { p = item.head_buf; } else if (S_DATA_READING == item.state) { p = item.data; } BGCC_TRACE("bgcc", "Enter SSL DataCallback(fd=%d)", fd); if (!callbackArg->ssl) { BGCC_TRACE("bgcc", "callbackArg->ssl is NULL, we should not be here."); TimeUtil::safe_sleep_ms(0); BGCC_TRACE("bgcc", "Leave SSL DataCallback(fd=%d)", fd); return; } bool do_while = true; while (true && do_while) { ret = SSL_read(callbackArg->ssl, p + item.nread, item.nexpected); switch(SSL_get_error(callbackArg->ssl, ret)) { case SSL_ERROR_NONE: item.nread += ret; item.nexpected -= ret; if (0 == item.nexpected) { if (S_SIZE_READING == item.state) { if (item.head_buf[0] != 'b' || item.head_buf[1] != 'g' || item.head_buf[2] != 'c' || item.head_buf[3] != 'P') { BGCC_WARN("bgcc", "invalid bgcc header(fd=%d)", fd); pItem->err = -1; do_while = false; break; } item.state = S_DATA_READING; item.nexpected = BODY_LEN(p); if (item.nexpected < 0) { BGCC_WARN("bgcc", "Message body length=%d too short, remove from epoll", item.nexpected); do_while = false; break; } else if (0 == item.nexpected) { BGCC_TRACE("bgcc", "Empty body Package"); do_while = false; break; } item.data = (char*)mempool->get_mem_block(item.nexpected); p = item.data; item.nread = 0; continue; } else if (S_DATA_READING == item.state) { pItem->err = 0; do_while = false; break; } } continue; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return; default: pItem->err = -1; do_while = false; break; } } SSLEpollServer* pArg = (SSLEpollServer*)callbackArg->arg; TaskAsso* pT = pArg ? pArg->Tasks+fd : NULL; pT->pLoop = el; pT->pServer = pArg; pT->pItem = pItem; PrepareEvent(pT->event, fd, arg); pItem->pTask = pT; int32_t todel = 1; BusizProcessor::Process(pItem, pT, item.nread, &todel, true, arg); if (pItem->err) { SSL_shutdown(callbackArg->ssl); BGCC_DEBUG("bgcc", "Memory SSL free: %p", callbackArg->ssl); SSL_free(callbackArg->ssl); callbackArg->ssl = NULL; if (pItem->isEnroll) { if(todel){ BGCC_WARN("bgcc", "Other Party is Closed Or Protocol Is Invalid, Force To Release fd=%d", fd); SharedPointer<BinaryProtocol> proto = SharedPointer<BinaryProtocol>( new BinaryProtocol( SharedPointer<ServerPeerSocket>( new ServerPeerSocket(fd) ))); SharedPointer<ConnInfo> info=SharedPointer<ConnInfo>( new ConnInfo(proto, pItem) ); if(proto.is_valid()&&info.is_valid()){ bgcc::ConnectionManager::get_instance()->put_connection(pItem->item.memo, info, true); } } } else { BGCC_WARN("bgcc", "Other Party is Closed Or Protocol Is Invalid, Force To Release fd=%d", fd); RemoveFD(el,fd); } } BGCC_TRACE("bgcc", "Leave SSL DataCallback(fd=%d)", fd); }
void bgcc::SSLEventCallback::AcceptCallback(EventLoop* el, SOCKET fd, void* arg) { BGCC_TRACE("bgcc", "Enter SSL AcceptCallback(fd=%d)", fd); do { SOCKET newfd = INVALID_SOCKET; struct sockaddr_in sin; socklen_t addrlen = sizeof(struct sockaddr); PeerInfo tmp("", 0); memset(&sin, 0, addrlen); newfd = accept(fd, (struct sockaddr*)&sin, &addrlen); if (INVALID_SOCKET != newfd) { SocketTool::getsockdetail(newfd, tmp, true); BGCC_NOTICE("bgcc", "Accept an Client From %s:%d, fd=%d", tmp.GetHost().c_str(), tmp.GetPort(), newfd); } else { if (SocketTool::is_interrupt()) { continue; } else { break; } } if (newfd >= MAXNFD) { BGCC_WARN("bgcc", "Too many client. Reject client %s:%d, fd=%d, (max=%d)", tmp.GetHost().c_str(), tmp.GetPort(), newfd, MAXNFD); SocketTool::close(newfd); BGCC_TRACE("bgcc", "Leave SSL AcceptCallback(fd=%d)", fd); return; } else { bgcc::ReadItem* pItem = &(Items[newfd]); pItem->Reset(); pItem->isEnroll = false; pItem->pTask = NULL; SSLEventCallbackArg* callbackArg = (SSLEventCallbackArg*)arg; SSLEventCallbackArg* newCallbackArg = &args[newfd]; newCallbackArg->arg = callbackArg->arg; newCallbackArg->ssl = SSL_new(g_ssl_ctx); BGCC_DEBUG("bgcc", "Memory new: %p", newCallbackArg->ssl); if (!newCallbackArg->ssl) { BGCC_WARN("bgcc", "new ssl failed. close fd=%d", newfd); SocketTool::close(newfd); break; } SSL_set_fd(newCallbackArg->ssl, newfd); Event e; PrepareEvent(e, newfd, newCallbackArg); e.read_cb = SSLAcceptCallback; if (el->add_event(&e) != 0) { SSL_shutdown(newCallbackArg->ssl); BGCC_DEBUG("bgcc", "Memory SSL free: %p", newCallbackArg->ssl); SSL_free(newCallbackArg->ssl); newCallbackArg->ssl = NULL; SocketTool::close(newfd); BGCC_TRACE("bgcc", "ssl add_event failed"); } } } while (true); BGCC_TRACE("bgcc", "Leave SSL AcceptCallback(fd=%d)", fd); }
ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c) { int n, sslerr; ngx_uint_t again; if (c->timedout) { SSL_set_shutdown(c->ssl->ssl, SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN); } else { if (c->ssl->no_rcv_shut) { SSL_set_shutdown(c->ssl->ssl, SSL_RECEIVED_SHUTDOWN); } if (c->ssl->no_send_shut) { SSL_set_shutdown(c->ssl->ssl, SSL_SENT_SHUTDOWN); } } again = 0; for ( ;; ) { n = SSL_shutdown(c->ssl->ssl); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); if (n == 0) { again = 1; break; } if (n == 1) { SSL_free(c->ssl->ssl); c->ssl = NULL; return NGX_OK; } break; } if (!again) { sslerr = SSL_get_error(c->ssl->ssl, n); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); } if (again || sslerr == SSL_ERROR_WANT_READ) { ngx_add_timer(c->read, 10000); if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_AGAIN; } if (sslerr == SSL_ERROR_WANT_WRITE) { if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_AGAIN; } ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_shutdown() failed"); return NGX_ERROR; }
bool SSLTCPSocket::setFD(SOCKET sock) { this->sock = sock; switch(endPoint) { case CLIENT: if ((ssl = SSL_new(SSLTCPSocket::clientContext)) == NULL) { fprintf(stderr, "SSL_new failed!\n"); CloseSocket(sock); return false; } break; case SERVER: if ((ssl = SSL_new(SSLTCPSocket::serverContext)) == NULL) { fprintf(stderr, "SSL_new failed!\n"); CloseSocket(sock); return false; } break; case LISTENER: default: return true; }; if (!SSL_set_fd(ssl, sock)) { fprintf(stderr, "SSL_set_fd failed!\n"); SSL_shutdown(ssl); SSL_free(ssl); CloseSocket(sock); return false; } int ret; bool handshaking = true; switch(endPoint) { case CLIENT: while (handshaking) { ret = SSL_connect(ssl); if (ret <= 0 && SSL_get_error(ssl, ret) != SSL_ERROR_WANT_CONNECT) { fprintf(stderr, "SSL_connect failed!\n"); this->error = -1; SSL_shutdown(ssl); SSL_free(ssl); ssl = NULL; CloseSocket(sock); return false; } else if (ret <= 0 && SSL_get_error(ssl, ret) == SSL_ERROR_WANT_CONNECT) { continue; } else { handshaking = false; } } break; case SERVER: while (handshaking) { ret = SSL_accept(ssl); if (ret <= 0 && SSL_get_error(ssl, ret) != SSL_ERROR_WANT_ACCEPT) { fprintf(stderr, "SSL_accept failed!\n"); ERR_print_errors_fp(stderr); this->error = -1; SSL_shutdown(ssl); SSL_free(ssl); ssl = NULL; CloseSocket(sock); return false; } else if (ret <= 0 && SSL_get_error(ssl, ret) == SSL_ERROR_WANT_ACCEPT) { continue; } else { handshaking = false; } } break; }; return true; }
int main(int argc, char **argv) { int sockfd, new_fd; socklen_t len; SSL *ssl; struct user *node; struct sockaddr_in my_addr, their_addr; unsigned int myport,lisnum; int result; result = pthread_mutex_init(&work_mutex,NULL);//initialize the mutex if (argv[1]) myport = atoi(argv[1]); else myport = 7838; if (argv[2]) lisnum = atoi(argv[2]); else lisnum = LISNUM; //the max number of connected client /*SSl initialize*/ SSL_library_init(); OpenSSL_add_all_algorithms(); /*load algorithms of SSL*/ SSL_load_error_strings(); /*load error infor*/ /*create a ssl_ctx */ ctx = SSL_CTX_new(SSLv23_server_method()); if(ctx == NULL) { ERR_print_errors_fp(stdout); exit(1); } /*certificate the user's ctx*/ if(SSL_CTX_use_certificate_file(ctx, argv[4], SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stdout); exit(1); } /*load privatekey*/ if(SSL_CTX_use_PrivateKey_file(ctx, argv[5], SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stdout); exit(1); } /*certificate privatekey*/ if(!SSL_CTX_check_private_key(ctx)) { ERR_print_errors_fp(stdout); exit(1); } /*create a socket*/ if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); }else printf("socket created\n"); bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(myport); if (argv[3]) my_addr.sin_addr.s_addr = inet_addr(argv[3]); else my_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) { perror("bind"); exit(1); } else printf("binded\n"); if (listen(sockfd, LISNUM) == -1) { perror("listen"); exit(1); } else printf("begin listen\n"); /*initialize signal*/ sigemptyset(&set); sigaddset(&set,SIGUSR1); sigaddset(&set,SIGUSR2); sigprocmask(SIG_SETMASK,&set,NULL); inituser(&root); //初始化用户链表 while (1) { len = sizeof(struct sockaddr); /*accept connection*/ if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len)) == -1) { perror("accept"); exit(errno); }else{ printf("server: got connection from %s, port %d, socket %d\n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd); /*create a new ssl*/ ssl = SSL_new(ctx); /*combinate the ssl with asocket*/ SSL_set_fd(ssl, new_fd); /*create a safe connection*/ if (SSL_accept(ssl) == -1) { perror("accept"); break; } /*create a thread to solve the communication*/ node = beforechat(&ssl); pthread_mutex_lock(&work_mutex); result = pthread_create(thread+(count++),NULL,recv_data,node); r_thread = thread[count-1]; pthread_kill(r_thread,SIGUSR1); //pthread_create(thread+(count++),NULL,send_data,ssl); if(result !=0){ perror("pthread_create"); exit(EXIT_FAILURE); } //send_data(ssl); pthread_mutex_unlock(&work_mutex); } } if(ssl != NULL) { SSL_shutdown(ssl); SSL_free(ssl); } close(sockfd); SSL_CTX_free(ctx); return 0; }
static void openssl_example_task(void *p) { int ret; SSL_CTX *ctx; SSL *ssl; int sockfd; struct sockaddr_in sock_addr; struct hostent *hp; struct ip4_addr *ip4_addr; int recv_bytes = 0; char recv_buf[OPENSSL_EXAMPLE_RECV_BUF_LEN]; const char send_data[] = OPENSSL_EXAMPLE_REQUEST; const int send_bytes = sizeof(send_data); ESP_LOGI(TAG, "OpenSSL demo thread start OK"); ESP_LOGI(TAG, "get target IP address"); hp = gethostbyname(OPENSSL_EXAMPLE_TARGET_NAME); if (!hp) { ESP_LOGI(TAG, "failed"); goto failed1; } ESP_LOGI(TAG, "OK"); ip4_addr = (struct ip4_addr *)hp->h_addr; ESP_LOGI(TAG, IPSTR, IP2STR(ip4_addr)); ESP_LOGI(TAG, "create SSL context ......"); ctx = SSL_CTX_new(TLSv1_1_client_method()); if (!ctx) { ESP_LOGI(TAG, "failed"); goto failed1; } ESP_LOGI(TAG, "OK"); ESP_LOGI(TAG, "create socket ......"); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { ESP_LOGI(TAG, "failed"); goto failed2; } ESP_LOGI(TAG, "OK"); ESP_LOGI(TAG, "bind socket ......"); memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = 0; sock_addr.sin_port = htons(OPENSSL_EXAMPLE_LOCAL_TCP_PORT); ret = bind(sockfd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); if (ret) { ESP_LOGI(TAG, "failed"); goto failed3; } ESP_LOGI(TAG, "OK"); ESP_LOGI(TAG, "socket connect to remote %s ......", OPENSSL_EXAMPLE_TARGET_NAME); memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = ip4_addr->addr; sock_addr.sin_port = htons(OPENSSL_EXAMPLE_TARGET_TCP_PORT); ret = connect(sockfd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); if (ret) { ESP_LOGI(TAG, "failed"); goto failed3; } ESP_LOGI(TAG, "OK"); ESP_LOGI(TAG, "create SSL ......"); ssl = SSL_new(ctx); if (!ssl) { ESP_LOGI(TAG, "failed"); goto failed3; } ESP_LOGI(TAG, "OK"); SSL_set_fd(ssl, sockfd); ESP_LOGI(TAG, "SSL connected to %s port %d ......", OPENSSL_EXAMPLE_TARGET_NAME, OPENSSL_EXAMPLE_TARGET_TCP_PORT); ret = SSL_connect(ssl); if (!ret) { ESP_LOGI(TAG, "failed " ); goto failed4; } ESP_LOGI(TAG, "OK"); ESP_LOGI(TAG, "send https request to %s port %d ......", OPENSSL_EXAMPLE_TARGET_NAME, OPENSSL_EXAMPLE_TARGET_TCP_PORT); ret = SSL_write(ssl, send_data, send_bytes); if (ret <= 0) { ESP_LOGI(TAG, "failed"); goto failed5; } ESP_LOGI(TAG, "OK"); do { ret = SSL_read(ssl, recv_buf, OPENSSL_EXAMPLE_RECV_BUF_LEN - 1); if (ret <= 0) { break; } recv_buf[ret] = '\0'; recv_bytes += ret; ESP_LOGI(TAG, "%s", recv_buf); } while (1); ESP_LOGI(TAG, "totaly read %d bytes data from %s ......", recv_bytes, OPENSSL_EXAMPLE_TARGET_NAME); failed5: SSL_shutdown(ssl); failed4: SSL_free(ssl); ssl = NULL; failed3: close(sockfd); sockfd = -1; failed2: SSL_CTX_free(ctx); ctx = NULL; failed1: vTaskDelete(NULL); return ; }
/****************************** transfer data */ static int transfer(CLI *c) { int num, err; int check_SSL_pending; enum {CL_OPEN, CL_INIT, CL_RETRY, CL_CLOSED} ssl_closing=CL_OPEN; int watchdog=0; /* a counter to detect an infinite loop */ int stunnel_hdr_is_sent=0; int insert_new_hdr=0; int is_http=-1; // -1:not set, 0:not http header, 1:is http header int space_cnt=0; char* space=NULL; char* first_hdr_end=NULL; c->sock_ptr=c->ssl_ptr=0; sock_rd=sock_wr=ssl_rd=ssl_wr=1; c->sock_bytes=c->ssl_bytes=0; do { /* main loop */ /* set flag to try and read any buffered SSL data * if we made room in the buffer by writing to the socket */ check_SSL_pending=0; /****************************** setup c->fds structure */ s_poll_zero(&c->fds); /* Initialize the structure */ if(sock_rd && c->sock_ptr<BUFFSIZE) /* socket input buffer not full*/ s_poll_add(&c->fds, c->sock_rfd->fd, 1, 0); if((ssl_rd && c->ssl_ptr<BUFFSIZE) || /* SSL input buffer not full */ ((c->sock_ptr || ssl_closing==CL_RETRY) && want_rd)) /* want to SSL_write or SSL_shutdown but read from the * underlying socket needed for the SSL protocol */ s_poll_add(&c->fds, c->ssl_rfd->fd, 1, 0); if(c->ssl_ptr) /* SSL input buffer not empty */ s_poll_add(&c->fds, c->sock_wfd->fd, 0, 1); if(c->sock_ptr || /* socket input buffer not empty */ ssl_closing==CL_INIT /* need to send close_notify */ || ((c->ssl_ptr<BUFFSIZE || ssl_closing==CL_RETRY) && want_wr)) /* want to SSL_read or SSL_shutdown but write to the * underlying socket needed for the SSL protocol */ s_poll_add(&c->fds, c->ssl_wfd->fd, 0, 1); /****************************** wait for an event */ err=s_poll_wait(&c->fds, (sock_rd && ssl_rd) /* both peers open */ || c->ssl_ptr /* data buffered to write to socket */ || c->sock_ptr /* data buffered to write to SSL */ ? c->opt->timeout_idle : c->opt->timeout_close); switch(err) { case -1: sockerror("transfer: s_poll_wait"); return -1; case 0: /* timeout */ if((sock_rd && ssl_rd) || c->ssl_ptr || c->sock_ptr) { s_log(LOG_INFO, "s_poll_wait timeout: connection reset"); return -1; } else { /* already closing connection */ s_log(LOG_INFO, "s_poll_wait timeout: connection close"); return 0; /* OK */ } } if(!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) { s_log(LOG_ERR, "INTERNAL ERROR: " "s_poll_wait returned %d, but no descriptor is ready", err); return -1; } /****************************** send SSL close_notify message */ if(ssl_closing==CL_INIT || (ssl_closing==CL_RETRY && ((want_rd && ssl_can_rd) || (want_wr && ssl_can_wr)))) { switch(SSL_shutdown(c->ssl)) { /* Send close_notify */ case 1: /* the shutdown was successfully completed */ s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify"); ssl_closing=CL_CLOSED; /* done! */ break; case 0: /* the shutdown is not yet finished */ s_log(LOG_DEBUG, "SSL_shutdown retrying"); ssl_closing=CL_RETRY; /* retry next time */ break; case -1: /* a fatal error occurred */ sslerror("SSL_shutdown"); return -1; } } /****************************** write to socket */ if(sock_wr && sock_can_wr) { /* for stunnel to tell web server the remote ip address */ int write_len; char real_remote_addr[IPLEN+2]; char addr_header[64]; char* colon; if(is_http == -1 && !stunnel_hdr_is_sent) { space = c->ssl_buff; for(; space_cnt < 2; space_cnt++) { space = strchr(space, ' '); if(space == NULL) break; else if(space - c->ssl_buff > c->ssl_ptr - 1) { space = NULL; break; } space++; } if(space_cnt == 2) { if(strncmp(space, "HTTP/", strlen("HTTP/"))==0) is_http = 1; else is_http = 0; } } if(is_http == 1 && !stunnel_hdr_is_sent) { first_hdr_end = strstr(c->ssl_buff, "\r\n"); if(first_hdr_end - c->ssl_buff <= c->ssl_ptr - strlen("\r\n")) insert_new_hdr = 1; } if(insert_new_hdr == 1) { first_hdr_end += 2; write_len = (int)first_hdr_end - (int)c->ssl_buff; num = writesocket(c->sock_wfd->fd, c->ssl_buff, write_len); //fprintf(stderr, "1: %d, %d\n", num, write_len); s_ntop(real_remote_addr, &c->peer_addr.addr[0]); colon = strchr(real_remote_addr, ':'); real_remote_addr[(int)colon - (int)real_remote_addr] = '\0'; sprintf(addr_header, "StunnelRemoteIP: %s\r\n", real_remote_addr); writesocket(c->sock_wfd->fd, addr_header, strlen(addr_header)); //fprintf(stderr, "2: %d, %d, %s\n", num, strlen(addr_header), addr_header); write_len = c->ssl_ptr - write_len; num += writesocket(c->sock_wfd->fd, first_hdr_end, write_len); //fprintf(stderr, "3: %d, %d\n", num, write_len); stunnel_hdr_is_sent = 1; insert_new_hdr = 0; } else { num = writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr); } switch(num) { case -1: /* error */ if(parse_socket_error("writesocket")) return -1; break; case 0: s_log(LOG_DEBUG, "No data written to the socket: retrying"); break; default: memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num); if(c->ssl_ptr==BUFFSIZE) /* buffer was previously full */ check_SSL_pending=1; /* check for data buffered by SSL */ c->ssl_ptr-=num; c->sock_bytes+=num; watchdog=0; /* reset watchdog */ } } /****************************** write to SSL */ if(ssl_wr && c->sock_ptr && ( /* output buffer not empty */ ssl_can_wr || (want_rd && ssl_can_rd) /* SSL_write wants to read from the underlying descriptor */ )) { num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr); switch(err=SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num); c->sock_ptr-=num; c->ssl_bytes+=num; watchdog=0; /* reset watchdog */ break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_write returned WANT_WRITE: retrying"); break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying"); break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_write returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: /* really an error */ if(num && parse_socket_error("SSL_write")) return -1; break; case SSL_ERROR_ZERO_RETURN: /* close_notify received */ s_log(LOG_DEBUG, "SSL closed on SSL_write"); ssl_rd=0; break; case SSL_ERROR_SSL: sslerror("SSL_write"); return -1; default: s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); return -1; } } /****************************** read from socket */ if(sock_rd && sock_can_rd) { num=readsocket(c->sock_rfd->fd, c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr); switch(num) { case -1: if(parse_socket_error("readsocket")) return -1; break; case 0: /* close */ s_log(LOG_DEBUG, "Socket closed on read"); sock_rd=0; break; default: c->sock_ptr+=num; watchdog=0; /* reset watchdog */ } } /****************************** read from SSL */ if(ssl_rd && c->ssl_ptr<BUFFSIZE && ( /* input buffer not full */ ssl_can_rd || (want_wr && ssl_can_wr) || /* SSL_read wants to write to the underlying descriptor */ (check_SSL_pending && SSL_pending(c->ssl)) /* write made space from full buffer */ )) { num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr); switch(err=SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: c->ssl_ptr+=num; watchdog=0; /* reset watchdog */ break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying"); break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_read returned WANT_READ: retrying"); break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_read returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: if(!num) { /* EOF */ if(c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed with %d byte(s) in buffer", c->sock_ptr); return -1; /* reset the socket */ } s_log(LOG_DEBUG, "SSL socket closed on SSL_read"); ssl_rd=ssl_wr=0; /* buggy or SSLv2 peer: no close_notify */ ssl_closing=CL_CLOSED; /* don't try to send it back */ } else if(parse_socket_error("SSL_read")) return -1; break; case SSL_ERROR_ZERO_RETURN: /* close_notify received */ s_log(LOG_DEBUG, "SSL closed on SSL_read"); ssl_rd=0; break; case SSL_ERROR_SSL: sslerror("SSL_read"); return -1; default: s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); return -1; } } /****************************** check write shutdown conditions */ if(sock_wr && !ssl_rd && !c->ssl_ptr) { s_log(LOG_DEBUG, "Socket write shutdown"); sock_wr=0; /* no further write allowed */ shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */ } if(ssl_wr && (!sock_rd || SSL_get_shutdown(c->ssl)) && !c->sock_ptr) { s_log(LOG_DEBUG, "SSL write shutdown"); ssl_wr=0; /* no further write allowed */ if(strcmp(SSL_get_version(c->ssl), "SSLv2")) { /* SSLv3, TLSv1 */ ssl_closing=CL_INIT; /* initiate close_notify */ } else { /* no alerts in SSLv2 including close_notify alert */ shutdown(c->sock_rfd->fd, SHUT_RD); /* notify the kernel */ shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */ SSL_set_shutdown(c->ssl, /* notify the OpenSSL library */ SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); ssl_rd=0; /* no further read allowed */ ssl_closing=CL_CLOSED; /* closed */ } } if(ssl_closing==CL_RETRY) { /* SSL shutdown */ if(!want_rd && !want_wr) { /* close_notify alert was received */ s_log(LOG_DEBUG, "SSL doesn't need to read or write"); ssl_closing=CL_CLOSED; } if(watchdog>5) { s_log(LOG_NOTICE, "Too many retries on SSL shutdown"); ssl_closing=CL_CLOSED; } } /****************************** check watchdog */ if(++watchdog>100) { /* loop executes without transferring any data */ s_log(LOG_ERR, "transfer() loop executes not transferring any data"); s_log(LOG_ERR, "please report the problem to [email protected]"); s_log(LOG_ERR, "socket open: rd=%s wr=%s, ssl open: rd=%s wr=%s", sock_rd ? "yes" : "no", sock_wr ? "yes" : "no", ssl_rd ? "yes" : "no", ssl_wr ? "yes" : "no"); s_log(LOG_ERR, "socket ready: rd=%s wr=%s, ssl ready: rd=%s wr=%s", sock_can_rd ? "yes" : "no", sock_can_wr ? "yes" : "no", ssl_can_rd ? "yes" : "no", ssl_can_wr ? "yes" : "no"); s_log(LOG_ERR, "ssl want: rd=%s wr=%s", want_rd ? "yes" : "no", want_wr ? "yes" : "no"); s_log(LOG_ERR, "socket input buffer: %d byte(s), " "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr); s_log(LOG_ERR, "check_SSL_pending=%d, ssl_closing=%d", check_SSL_pending, ssl_closing); return -1; } } while(sock_wr || ssl_closing!=CL_CLOSED); return 0; /* OK */ }
/* Asynchronous SSL stream reader */ int ssl_read_thread(thread_t * thread) { checker_t *checker = THREAD_ARG(thread); http_checker_t *http_get_check = CHECKER_ARG(checker); http_arg_t *http_arg = HTTP_ARG(http_get_check); request_t *req = HTTP_REQ(http_arg); unsigned char digest[16]; int r = 0; int val; /* Handle read timeout */ if (thread->type == THREAD_READ_TIMEOUT && !req->extracted) return timeout_epilog(thread, "=> SSL CHECK failed on service" " : recevice data <=\n\n", "SSL read"); /* Set descriptor non blocking */ val = fcntl(thread->u.fd, F_GETFL, 0); fcntl(thread->u.fd, F_SETFL, val | O_NONBLOCK); /* read the SSL stream */ r = SSL_read(req->ssl, req->buffer + req->len, MAX_BUFFER_LENGTH - req->len); /* restore descriptor flags */ fcntl(thread->u.fd, F_SETFL, val); req->error = SSL_get_error(req->ssl, r); if (req->error == SSL_ERROR_WANT_READ) { /* async read unfinished */ thread_add_read(thread->master, ssl_read_thread, checker, thread->u.fd, http_get_check->connection_to); } else if (r > 0 && req->error == 0) { /* Handle response stream */ http_process_response(req, r); /* * Register next ssl stream reader. * Register itself to not perturbe global I/O multiplexer. */ thread_add_read(thread->master, ssl_read_thread, checker, thread->u.fd, http_get_check->connection_to); } else if (req->error) { /* All the SSL streal has been parsed */ MD5_Final(digest, &req->context); SSL_set_quiet_shutdown(req->ssl, 1); r = (req->error == SSL_ERROR_ZERO_RETURN) ? SSL_shutdown(req->ssl) : 0; if (r && !req->extracted) { /* check if server is currently alive */ if (svr_checker_up(checker->id, checker->rs)) { smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> SSL CHECK failed on service" " : cannot receive data <=\n\n"); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } return epilog(thread, 1, 0, 0); } /* Handle response stream */ http_handle_response(thread, digest, (!req->extracted) ? 1 : 0); } return 0; }
int connection_state_machine(server *srv, connection *con) { int done = 0, r; #ifdef USE_OPENSSL server_socket *srv_sock = con->srv_socket; #endif if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state at start", con->fd, connection_get_state(con->state)); } while (done == 0) { size_t ostate = con->state; switch (con->state) { case CON_STATE_REQUEST_START: /* transient */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } con->request_start = srv->cur_ts; con->read_idle_ts = srv->cur_ts; con->request_count++; con->loops_per_request = 0; connection_set_state(srv, con, CON_STATE_READ); /* patch con->conf.is_ssl if the connection is a ssl-socket already */ #ifdef USE_OPENSSL con->conf.is_ssl = srv_sock->is_ssl; #endif break; case CON_STATE_REQUEST_END: /* transient */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } buffer_reset(con->uri.authority); buffer_reset(con->uri.path); buffer_reset(con->uri.query); buffer_reset(con->request.orig_uri); if (http_request_parse(srv, con)) { /* we have to read some data from the POST request */ connection_set_state(srv, con, CON_STATE_READ_POST); break; } connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); break; case CON_STATE_HANDLE_REQUEST: /* * the request is parsed * * decided what to do with the request * - * * */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } switch (r = http_response_prepare(srv, con)) { case HANDLER_FINISHED: if (con->mode == DIRECT) { if (con->http_status == 404 || con->http_status == 403) { /* 404 error-handler */ if (con->in_error_handler == 0 && (!buffer_is_empty(con->conf.error_handler) || !buffer_is_empty(con->error_handler))) { /* call error-handler */ con->error_handler_saved_status = con->http_status; con->http_status = 0; if (buffer_is_empty(con->error_handler)) { buffer_copy_string_buffer(con->request.uri, con->conf.error_handler); } else { buffer_copy_string_buffer(con->request.uri, con->error_handler); } buffer_reset(con->physical.path); con->in_error_handler = 1; connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); done = -1; break; } else if (con->in_error_handler) { /* error-handler is a 404 */ con->http_status = con->error_handler_saved_status; } } else if (con->in_error_handler) { /* error-handler is back and has generated content */ /* if Status: was set, take it otherwise use 200 */ } } if (con->http_status == 0) con->http_status = 200; /* we have something to send, go on */ connection_set_state(srv, con, CON_STATE_RESPONSE_START); break; case HANDLER_WAIT_FOR_FD: srv->want_fds++; fdwaitqueue_append(srv, con); connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); break; case HANDLER_COMEBACK: done = -1; case HANDLER_WAIT_FOR_EVENT: /* come back here */ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); break; case HANDLER_ERROR: /* something went wrong */ connection_set_state(srv, con, CON_STATE_ERROR); break; default: log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r); break; } break; case CON_STATE_RESPONSE_START: /* * the decision is done * - create the HTTP-Response-Header * */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } if (-1 == connection_handle_write_prepare(srv, con)) { connection_set_state(srv, con, CON_STATE_ERROR); break; } connection_set_state(srv, con, CON_STATE_WRITE); break; case CON_STATE_RESPONSE_END: /* transient */ /* log the request */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } plugins_call_handle_request_done(srv, con); srv->con_written++; if (con->keep_alive) { connection_set_state(srv, con, CON_STATE_REQUEST_START); #if 0 con->request_start = srv->cur_ts; con->read_idle_ts = srv->cur_ts; #endif } else { switch(r = plugins_call_handle_connection_close(srv, con)) { case HANDLER_GO_ON: case HANDLER_FINISHED: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r); break; } #ifdef USE_OPENSSL if (srv_sock->is_ssl) { switch (SSL_shutdown(con->ssl)) { case 1: /* done */ break; case 0: /* wait for fd-event * * FIXME: wait for fdevent and call SSL_shutdown again * */ break; default: log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); } } #endif if ((0 == shutdown(con->fd, SHUT_WR))) { con->close_timeout_ts = srv->cur_ts; connection_set_state(srv, con, CON_STATE_CLOSE); } else { connection_close(srv, con); } srv->con_closed++; } connection_reset(srv, con); break; case CON_STATE_CONNECT: if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } chunkqueue_reset(con->read_queue); con->request_count = 0; break; case CON_STATE_CLOSE: if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } /* we have to do the linger_on_close stuff regardless * of con->keep_alive; even non-keepalive sockets may * still have unread data, and closing before reading * it will make the client not see all our output. */ { int len; char buf[1024]; len = read(con->fd, buf, sizeof(buf)); if (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) { con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1); } } if (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) { connection_close(srv, con); if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed for fd", con->fd); } } break; case CON_STATE_READ_POST: case CON_STATE_READ: if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } connection_handle_read_state(srv, con); break; case CON_STATE_WRITE: if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } /* only try to write if we have something in the queue */ if (!chunkqueue_is_empty(con->write_queue)) { #if 0 log_error_write(srv, __FILE__, __LINE__, "dsd", con->fd, "packets to write:", con->write_queue->used); #endif } if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) { if (-1 == connection_handle_write(srv, con)) { log_error_write(srv, __FILE__, __LINE__, "ds", con->fd, "handle write failed."); connection_set_state(srv, con, CON_STATE_ERROR); } } break; case CON_STATE_ERROR: /* transient */ /* even if the connection was drop we still have to write it to the access log */ if (con->http_status) { plugins_call_handle_request_done(srv, con); } #ifdef USE_OPENSSL if (srv_sock->is_ssl) { int ret, ssl_r; unsigned long err; ERR_clear_error(); switch ((ret = SSL_shutdown(con->ssl))) { case 1: /* ok */ break; case 0: ERR_clear_error(); if (-1 != (ret = SSL_shutdown(con->ssl))) break; /* fall through */ default: switch ((ssl_r = SSL_get_error(con->ssl, ret))) { case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: break; case SSL_ERROR_SYSCALL: /* perhaps we have error waiting in our error-queue */ if (0 != (err = ERR_get_error())) { do { log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", ssl_r, ret, ERR_error_string(err, NULL)); } while((err = ERR_get_error())); } else if (errno != 0) { /* ssl bug (see lighttpd ticket #2213): sometimes errno == 0 */ switch(errno) { case EPIPE: case ECONNRESET: break; default: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", ssl_r, ret, errno, strerror(errno)); break; } } break; default: while((err = ERR_get_error())) { log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", ssl_r, ret, ERR_error_string(err, NULL)); } break; } } ERR_clear_error(); } #endif switch(con->mode) { case DIRECT: #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "emergency exit: direct", con->fd); #endif break; default: switch(r = plugins_call_handle_connection_close(srv, con)) { case HANDLER_GO_ON: case HANDLER_FINISHED: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r); break; } break; } connection_reset(srv, con); /* close the connection */ if ((0 == shutdown(con->fd, SHUT_WR))) { con->close_timeout_ts = srv->cur_ts; connection_set_state(srv, con, CON_STATE_CLOSE); if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sd", "shutdown for fd", con->fd); } } else { connection_close(srv, con); } con->keep_alive = 0; srv->con_closed++; break; default: log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown state:", con->fd, con->state); break; } if (done == -1) { done = 0; } else if (ostate == con->state) { done = 1; } } if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state at exit:", con->fd, connection_get_state(con->state)); } switch(con->state) { case CON_STATE_READ_POST: case CON_STATE_READ: case CON_STATE_CLOSE: fdevent_event_set(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN); break; case CON_STATE_WRITE: /* request write-fdevent only if we really need it * - if we have data to write * - if the socket is not writable yet */ if (!chunkqueue_is_empty(con->write_queue) && (con->is_writable == 0) && (con->traffic_limit_reached == 0)) { fdevent_event_set(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT); } else { fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); } break; default: fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); break; } return 0; }
/* * Fetches the resource denoted by |uri|. */ static void fetch_uri(const struct URI *uri) { nghttp2_session_callbacks *callbacks; int fd; SSL_CTX *ssl_ctx; SSL *ssl; struct Request req; struct Connection connection; int rv; nfds_t npollfds = 1; struct pollfd pollfds[1]; request_init(&req, uri); /* Establish connection and setup SSL */ fd = connect_to(req.host, req.port); if (fd == -1) { die("Could not open file descriptor"); } ssl_ctx = SSL_CTX_new(SSLv23_client_method()); if (ssl_ctx == NULL) { dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL)); } init_ssl_ctx(ssl_ctx); ssl = SSL_new(ssl_ctx); if (ssl == NULL) { dief("SSL_new", ERR_error_string(ERR_get_error(), NULL)); } /* To simplify the program, we perform SSL/TLS handshake in blocking I/O. */ ssl_handshake(ssl, fd); connection.ssl = ssl; connection.want_io = IO_NONE; /* Here make file descriptor non-block */ make_non_block(fd); set_tcp_nodelay(fd); printf("[INFO] SSL/TLS handshake completed\n"); rv = nghttp2_session_callbacks_new(&callbacks); if (rv != 0) { diec("nghttp2_session_callbacks_new", rv); } setup_nghttp2_callbacks(callbacks); rv = nghttp2_session_client_new(&connection.session, callbacks, &connection); nghttp2_session_callbacks_del(callbacks); if (rv != 0) { diec("nghttp2_session_client_new", rv); } rv = nghttp2_submit_settings(connection.session, NGHTTP2_FLAG_NONE, NULL, 0); if (rv != 0) { diec("nghttp2_submit_settings", rv); } /* Submit the HTTP request to the outbound queue. */ submit_request(&connection, &req); pollfds[0].fd = fd; ctl_poll(pollfds, &connection); /* Event loop */ while (nghttp2_session_want_read(connection.session) || nghttp2_session_want_write(connection.session)) { int nfds = poll(pollfds, npollfds, -1); if (nfds == -1) { dief("poll", strerror(errno)); } if (pollfds[0].revents & (POLLIN | POLLOUT)) { exec_io(&connection); } if ((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) { die("Connection error"); } ctl_poll(pollfds, &connection); } /* Resource cleanup */ nghttp2_session_del(connection.session); SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ssl_ctx); shutdown(fd, SHUT_WR); close(fd); request_free(&req); }
int main(int argc,char** argv){ // openssl support #ifdef _SSL initSSL(); ctx=SSL_CTX_new(SSLv23_client_method()); if(ctx==NULL){ ERR_print_errors_fp(stdout); exit(-2); } #endif if(argc!=2){ printf("Usage:client ipv6addr\n"); exit(-1); } setlocale(LC_ALL,""); char name[10]; printf("输入昵称:\n"); scanf("%6s",name); int sockfd,len; struct sockaddr_in6 dst; char buf[MAXBUF+1]; char buf1[MAXBUF+1]; sockfd=socket(AF_INET6,PROTOCOL,0); GUARD(sockfd); bzero(&dst,sizeof(dst)); dst.sin6_family=AF_INET6; dst.sin6_port=htons(SERVERPORT); GUARD(inet_pton(AF_INET6,argv[1],&dst.sin6_addr)); GUARD(connect(sockfd,(struct sockaddr *)&dst,sizeof(dst))); // ssl support #ifdef _SSL sslfd=SSL_new(ctx); SSL_set_fd(sslfd,sockfd); if(SSL_connect(sslfd)==-1) ERR_print_errors_fp(stderr); else{ printf("connected with %s encryption\n",SSL_get_cipher(sslfd)); //ShowCerts(sslfd); } #endif // ssl support bind over initscr(); WINDOW *recvBd=subwin(stdscr,HEIGHT1+2,WIDTH+2,1,1); WINDOW *inputBd=subwin(stdscr,HEIGHT+2,WIDTH+2,15,1); recvWin=subwin(stdscr,HEIGHT1,WIDTH,2,2); inputWin=subwin(stdscr,HEIGHT,WIDTH,16,2); box(recvBd,HLINE,VLINE); box(inputBd,HLINE,VLINE); wprintw(recvBd,"接收"); wprintw(inputBd,"发送"); cbreak(); keypad(stdscr,TRUE); start_color(); scrollok(recvWin,1); scrollok(inputWin,1); refresh(); bzero(buf,MAXBUF+1); #ifndef _SSL len=recv(sockfd,buf,MAXBUF,0); #else len=SSL_read(sslfd,buf,MAXBUF); #endif wprintw(recvWin,"%s\n",buf); touchwin(recvWin); wrefresh(recvWin); pthread_t t_recv; if(pthread_create(&t_recv,NULL,recvThread,(void*)sockfd)<0){ perror("create thread"); exit(1); } while(1){ bzero(buf,MAXBUF+1); wprintw(inputWin,"%6s > ",name); int key=wgetch(inputWin); if(key==ESCAPE){ break; } wscanw(inputWin,"%s",buf); touchwin(inputWin); wrefresh(inputWin); sprintf(buf1,"[%6s]: %c%s\n",name,(char)key,buf); #ifndef _SSL len=send(sockfd,buf1,strlen(buf1),0); #else len=SSL_write(sslfd,buf1,strlen(buf1)); #endif if(len<0) continue; } close(sockfd); delwin(recvWin); delwin(inputWin); delwin(recvBd); delwin(inputBd); endwin(); #ifdef _SSL SSL_shutdown(sslfd); SSL_free(sslfd); SSL_CTX_free(ctx); #endif return 0; }
/** Called on successful connections and errors */ void event_cb(struct bufferevent *bev, short e, void *data) { struct conn *c = data; uint32_t error_conditions = BEV_EVENT_EOF | BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT; #if SSL_DEBUG_LEVEL > 1 errprintf(stdout, "ssl_slave: event callback triggered with flags 0x%hx\n", e); #endif if (e & BEV_EVENT_CONNECTED) { if (c->local_bev == bev) { local_connected(c); } else { ssl_connected(c); } } else if (e & BEV_EVENT_TIMEOUT) { if (c->state == C_SSL_CONNECTING) { /* Handshake timed out. */ #if SSL_DEBUG_LEVEL > 0 errprintf(stdout, "ssl_slave: SSL handshake timeout.\n"); #endif bufferevent_disable(c->remote_bev, EV_READ | EV_WRITE); bufferevent_free(c->remote_bev); c->remote_bev = NULL; c->state = C_SHUTTINGDOWN; if (c->local_bev) { bufferevent_disable(c->local_bev, EV_READ); bufferevent_flush(c->local_bev, EV_WRITE, BEV_FINISHED); } delete_conn(c); } else { /* Bug in some versions of libevent cause this to trigger when it shouldn't. Ignore. */ return; } } else if (e & error_conditions) { if (c->local_bev == bev) { /* Mush side of the connection went away. Flush SSL buffer and shut down. */ #if SSL_DEBUG_LEVEL > 0 errprintf(stdout, "ssl_slave: Lost local connection. State: %d, reason 0x%hx.\n", c->state, e); #endif bufferevent_disable(c->local_bev, EV_READ | EV_WRITE); bufferevent_free(c->local_bev); c->local_bev = NULL; c->state = C_SHUTTINGDOWN; if (c->remote_bev) { bufferevent_disable(c->remote_bev, EV_READ); bufferevent_flush(c->remote_bev, EV_WRITE, BEV_FINISHED); SSL_shutdown(bufferevent_openssl_get_ssl(c->remote_bev)); } delete_conn(c); } else { /* Remote side of the connection went away. Flush mush buffer and shut down. */ #if SSL_DEBUG_LEVEL > 0 errprintf(stdout, "ssl_slave: Lost SSL connection. State: %d, reason 0x%hx.\n", c->state, e); #endif bufferevent_disable(c->remote_bev, EV_READ | EV_WRITE); bufferevent_free(c->remote_bev); c->remote_bev = NULL; c->state = C_SHUTTINGDOWN; if (c->local_bev) { bufferevent_disable(c->local_bev, EV_READ); bufferevent_flush(c->local_bev, EV_WRITE, BEV_FINISHED); } delete_conn(c); } } }
static void transfer(CLI * c) { int watchdog = 0; int num, err; int sock_open_rd = 1, sock_open_wr = 1; int shutdown_wants_read = 0, shutdown_wants_write = 0; int read_wants_read, read_wants_write = 0; int write_wants_read = 0, write_wants_write; int sock_can_rd, sock_can_wr, ssl_can_rd, ssl_can_wr; c->sock_ptr = c->ssl_ptr = 0; do { read_wants_read = !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN) && c->ssl_ptr < BUFFSIZE && !read_wants_write; write_wants_write = !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN) && c->sock_ptr && !write_wants_read; s_poll_init(c->fds); if (sock_open_rd) s_poll_add(c->fds, c->sock_rfd->fd, c->sock_ptr < BUFFSIZE, 0); if (sock_open_wr) s_poll_add(c->fds, c->sock_wfd->fd, 0, c->ssl_ptr); if (read_wants_read || write_wants_read || shutdown_wants_read) s_poll_add(c->fds, c->ssl_rfd->fd, 1, 0); if (read_wants_write || write_wants_write || shutdown_wants_write) s_poll_add(c->fds, c->ssl_wfd->fd, 0, 1); err = s_poll_wait(c->fds, (sock_open_rd && !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr || c->sock_ptr ? c->opt->timeout_idle : c->opt->timeout_close, 0); switch (err) { case -1: sockerror("transfer: s_poll_wait"); longjmp(c->err, 1); case 0: if ((sock_open_rd && !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr || c->sock_ptr) { s_log(LOG_INFO, "transfer: s_poll_wait:" " TIMEOUTidle exceeded: sending reset"); longjmp(c->err, 1); } else { s_log(LOG_ERR, "transfer: s_poll_wait:" " TIMEOUTclose exceeded: closing"); return; } } err = s_poll_error(c->fds, c->sock_rfd); if (err) { s_log(LOG_NOTICE, "Error detected on socket (read) file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } if (c->sock_wfd->fd != c->sock_rfd->fd) { err = s_poll_error(c->fds, c->sock_wfd); if (err) { s_log(LOG_NOTICE, "Error detected on socket write file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } } err = s_poll_error(c->fds, c->ssl_rfd); if (err) { s_log(LOG_NOTICE, "Error detected on SSL (read) file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } if (c->ssl_wfd->fd != c->ssl_rfd->fd) { err = s_poll_error(c->fds, c->ssl_wfd); if (err) { s_log(LOG_NOTICE, "Error detected on SSL write file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } } sock_can_rd = s_poll_canread(c->fds, c->sock_rfd->fd); sock_can_wr = s_poll_canwrite(c->fds, c->sock_wfd->fd); ssl_can_rd = s_poll_canread(c->fds, c->ssl_rfd->fd); ssl_can_wr = s_poll_canwrite(c->fds, c->ssl_wfd->fd); if (!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) { s_log(LOG_ERR, "INTERNAL ERROR: " "s_poll_wait returned %d, but no descriptor is ready", err); longjmp(c->err, 1); } if (shutdown_wants_read || shutdown_wants_write) { num = SSL_shutdown(c->ssl); if (num < 0) err = SSL_get_error(c->ssl, num); else err = SSL_ERROR_NONE; switch (err) { case SSL_ERROR_NONE: s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify alert"); shutdown_wants_read = shutdown_wants_write = 0; break; case SSL_ERROR_SYSCALL: if (parse_socket_error(c, "SSL_shutdown")) break; SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); shutdown_wants_read = shutdown_wants_write = 0; break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_shutdown returned WANT_WRITE: retrying"); shutdown_wants_read = 0; shutdown_wants_write = 1; break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_shutdown returned WANT_READ: retrying"); shutdown_wants_read = 1; shutdown_wants_write = 0; break; case SSL_ERROR_SSL: sslerror("SSL_shutdown"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_shutdown/SSL_get_error returned %d", err); longjmp(c->err, 1); } } if (sock_open_rd && sock_can_rd) { num = readsocket(c->sock_rfd->fd, c->sock_buff + c->sock_ptr, BUFFSIZE - c->sock_ptr); switch (num) { case -1: if (parse_socket_error(c, "readsocket")) break; case 0: s_log(LOG_DEBUG, "Socket closed on read"); sock_open_rd = 0; break; default: c->sock_ptr += num; watchdog = 0; } } if (sock_open_wr && sock_can_wr) { num = writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr); switch (num) { case -1: if (parse_socket_error(c, "writesocket")) break; case 0: s_log(LOG_DEBUG, "Socket closed on write"); sock_open_rd = sock_open_wr = 0; break; default: memmove(c->ssl_buff, c->ssl_buff + num, c->ssl_ptr - num); c->ssl_ptr -= num; c->sock_bytes += num; watchdog = 0; } } read_wants_read = !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN) && c->ssl_ptr < BUFFSIZE && !read_wants_write; write_wants_write = !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN) && c->sock_ptr && !write_wants_read; if ((read_wants_read && (ssl_can_rd || SSL_pending(c->ssl))) || (read_wants_write && ssl_can_wr)) { read_wants_write = 0; num = SSL_read(c->ssl, c->ssl_buff + c->ssl_ptr, BUFFSIZE - c->ssl_ptr); switch (err = SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: if (num == 0) s_log(LOG_DEBUG, "SSL_read returned 0"); c->ssl_ptr += num; watchdog = 0; break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying"); read_wants_write = 1; break; case SSL_ERROR_WANT_READ: break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_read returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: if (num && parse_socket_error(c, "SSL_read")) break; if (c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed on SSL_read with %d unsent byte(s)", c->sock_ptr); longjmp(c->err, 1); } s_log(LOG_DEBUG, "SSL socket closed on SSL_read"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_ZERO_RETURN: s_log(LOG_DEBUG, "SSL closed on SSL_read"); if (SSL_version(c->ssl) == SSL2_VERSION) SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_SSL: sslerror("SSL_read"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); longjmp(c->err, 1); } } if ((write_wants_read && ssl_can_rd) || (write_wants_write && ssl_can_wr)) { write_wants_read = 0; num = SSL_write(c->ssl, c->sock_buff, c->sock_ptr); switch (err = SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: if (num == 0) s_log(LOG_DEBUG, "SSL_write returned 0"); memmove(c->sock_buff, c->sock_buff + num, c->sock_ptr - num); c->sock_ptr -= num; c->ssl_bytes += num; watchdog = 0; break; case SSL_ERROR_WANT_WRITE: break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying"); write_wants_read = 1; break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_write returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: if (num && parse_socket_error(c, "SSL_write")) break; if (c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed on SSL_write with %d unsent byte(s)", c->sock_ptr); longjmp(c->err, 1); } s_log(LOG_DEBUG, "SSL socket closed on SSL_write"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_ZERO_RETURN: s_log(LOG_DEBUG, "SSL closed on SSL_write"); if (SSL_version(c->ssl) == SSL2_VERSION) SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_SSL: sslerror("SSL_write"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); longjmp(c->err, 1); } } if (sock_open_wr && SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN && !c->ssl_ptr) { sock_open_wr = 0; if (!c->sock_wfd->is_socket) { s_log(LOG_DEBUG, "Closing the socket file descriptor"); sock_open_rd = 0; } else if (!shutdown(c->sock_wfd->fd, SHUT_WR)) { s_log(LOG_DEBUG, "Sent socket write shutdown"); } else { s_log(LOG_DEBUG, "Failed to send socket write shutdown"); sock_open_rd = 0; } } if (!(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN) && !sock_open_rd && !c->sock_ptr) { if (SSL_version(c->ssl) != SSL2_VERSION) { s_log(LOG_DEBUG, "Sending close_notify alert"); shutdown_wants_write = 1; } else { s_log(LOG_DEBUG, "Closing SSLv2 socket"); if (c->ssl_rfd->is_socket) shutdown(c->ssl_rfd->fd, SHUT_RD); if (c->ssl_wfd->is_socket) shutdown(c->ssl_wfd->fd, SHUT_WR); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); } } if (++watchdog > 100) { s_log(LOG_ERR, "transfer() loop executes not transferring any data"); wifisec_info(LOG_ERR); s_log(LOG_ERR, "protocol=%s, SSL_pending=%d", SSL_get_version(c->ssl), SSL_pending(c->ssl)); s_log(LOG_ERR, "sock_open_rd=%s, sock_open_wr=%s", sock_open_rd ? "Y" : "n", sock_open_wr ? "Y" : "n"); s_log(LOG_ERR, "SSL_RECEIVED_SHUTDOWN=%s, SSL_SENT_SHUTDOWN=%s", SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN ? "Y" : "n", SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN ? "Y" : "n"); s_log(LOG_ERR, "sock_can_rd=%s, sock_can_wr=%s", sock_can_rd ? "Y" : "n", sock_can_wr ? "Y" : "n"); s_log(LOG_ERR, "ssl_can_rd=%s, ssl_can_wr=%s", ssl_can_rd ? "Y" : "n", ssl_can_wr ? "Y" : "n"); s_log(LOG_ERR, "read_wants_read=%s, read_wants_write=%s", read_wants_read ? "Y" : "n", read_wants_write ? "Y" : "n"); s_log(LOG_ERR, "write_wants_read=%s, write_wants_write=%s", write_wants_read ? "Y" : "n", write_wants_write ? "Y" : "n"); s_log(LOG_ERR, "shutdown_wants_read=%s, shutdown_wants_write=%s", shutdown_wants_read ? "Y" : "n", shutdown_wants_write ? "Y" : "n"); s_log(LOG_ERR, "socket input buffer: %d byte(s), " "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr); longjmp(c->err, 1); } } while (sock_open_wr || !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN) || shutdown_wants_read || shutdown_wants_write); }
void SSLSocket::shutdown() throw() { if(ssl) SSL_shutdown(ssl); }
int main(int argc, char **argv) { int sockfd = 0; int on = 1; struct sockaddr_in6 listen_addr = { AF_INET6, htons(20220), 0, IN6ADDR_ANY_INIT, 0 }; size_t addr_size = sizeof(struct sockaddr_in6); fd_set fds[2]; int result, flags; int idx, res = 0; struct timeval timeout; struct sigaction act, oact; #ifdef WITH_DTLS SSL_CTX *ctx; memset(ssl_peer_storage, 0, sizeof(ssl_peer_storage)); SSL_load_error_strings(); SSL_library_init(); ctx = SSL_CTX_new(DTLSv1_server_method()); SSL_CTX_set_cipher_list(ctx, "ALL"); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); res = SSL_CTX_use_certificate_file(ctx, SERVER_CERT_PEM, SSL_FILETYPE_PEM); if (res != 1) { fprintf(stderr, "cannot read server certificate from file '%s' (%s)\n", SERVER_CERT_PEM, ERR_error_string(res,NULL)); goto end; } res = SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY_PEM, SSL_FILETYPE_PEM); if (res != 1) { fprintf(stderr, "cannot read server key from file '%s' (%s)\n", SERVER_KEY_PEM, ERR_error_string(res,NULL)); goto end; } res = SSL_CTX_check_private_key (ctx); if (res != 1) { fprintf(stderr, "invalid private key\n"); goto end; } res = SSL_CTX_load_verify_locations(ctx, CA_CERT_PEM, NULL); if (res != 1) { fprintf(stderr, "cannot read ca file '%s'\n", CA_CERT_PEM); goto end; } /* Client has to authenticate */ /* Client has to authenticate */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL); SSL_CTX_set_read_ahead(ctx, 1); /* disable read-ahead */ SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie); SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie); SSL_CTX_use_psk_identity_hint(ctx, "Enter password for CoAP-Gateway"); SSL_CTX_set_psk_server_callback(ctx, psk_server_callback); SSL_CTX_set_info_callback(ctx, info_callback); #endif sockfd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0); if ( sockfd < 0 ) { perror("socket"); return -1; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) perror("setsockopt SO_REUSEADDR"); flags = fcntl(sockfd, F_GETFL, 0); if (flags < 0 || fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) { perror("fcntl"); return -1; } on = 1; if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) { perror("setsockopt IPV6_PKTINFO"); } if (bind (sockfd, (const struct sockaddr *)&listen_addr, addr_size) < 0) { perror("bind"); res = -2; goto end; } act.sa_handler = handle_sigint; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, &oact); while (!quit) { FD_ZERO(&fds[READ]); FD_ZERO(&fds[WRITE]); FD_SET(sockfd, &fds[READ]); timeout.tv_sec = 1; timeout.tv_usec = 0; result = select( FD_SETSIZE, &fds[READ], &fds[WRITE], 0, &timeout); if (result < 0) { /* error */ if (errno != EINTR) perror("select"); } else if (result > 0) { /* read from socket */ if ( FD_ISSET( sockfd, &fds[READ]) ) { _read(ctx, sockfd); /* read received data */ } else if ( FD_ISSET( sockfd, &fds[WRITE]) ) { /* write to socket */ _write(ctx, sockfd); /* write data */ } } else { /* timeout */ check_timeout(); } remove_closed(); } end: #ifdef WITH_DTLS for (idx = 0; idx < MAX_SSL_PEERS; idx++) { if (ssl_peer_storage[idx] && ssl_peer_storage[idx]->ssl) { if (ssl_peer_storage[idx]->state == PEER_ST_ESTABLISHED) SSL_shutdown(ssl_peer_storage[idx]->ssl); SSL_free(ssl_peer_storage[idx]->ssl); } } SSL_CTX_free(ctx); #endif close(sockfd); /* don't care if we close stdin at this point */ return res; }
netsnmp_transport * netsnmp_tlstcp_open(netsnmp_transport *t) { _netsnmpTLSBaseData *tlsdata; BIO *bio; SSL_CTX *ctx; SSL *ssl; int rc = 0; _netsnmp_verify_info *verify_info; netsnmp_assert_or_return(t != NULL, NULL); netsnmp_assert_or_return(t->data != NULL, NULL); netsnmp_assert_or_return(sizeof(_netsnmpTLSBaseData) == t->data_length, NULL); tlsdata = t->data; if (tlsdata->flags & NETSNMP_TLSBASE_IS_CLIENT) { /* Is the client */ /* RFC5953 Section 5.3.1: Establishing a Session as a Client * 1) The snmpTlstmSessionOpens counter is incremented. */ snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENS); /* RFC5953 Section 5.3.1: Establishing a Session as a Client 2) The client selects the appropriate certificate and cipher_suites for the key agreement based on the tmSecurityName and the tmRequestedSecurityLevel for the session. For sessions being established as a result of a SNMP-TARGET-MIB based operation, the certificate will potentially have been identified via the snmpTlstmParamsTable mapping and the cipher_suites will have to be taken from system-wide or implementation-specific configuration. If no row in the snmpTlstmParamsTable exists then implementations MAY choose to establish the connection using a default client certificate available to the application. Otherwise, the certificate and appropriate cipher_suites will need to be passed to the openSession() ASI as supplemental information or configured through an implementation-dependent mechanism. It is also implementation-dependent and possibly policy-dependent how tmRequestedSecurityLevel will be used to influence the security capabilities provided by the (D)TLS connection. However this is done, the security capabilities provided by (D)TLS MUST be at least as high as the level of security indicated by the tmRequestedSecurityLevel parameter. The actual security level of the session is reported in the tmStateReference cache as tmSecurityLevel. For (D)TLS to provide strong authentication, each principal acting as a command generator SHOULD have its own certificate. */ /* Implementation notes: we do most of this in the sslctx_client_setup The transport should have been f_config()ed with the proper fingerprints to use (which is stored in tlsdata), or we'll use the default identity fingerprint if that can be found. */ /* XXX: check securityLevel and ensure no NULL fingerprints are used */ /* set up the needed SSL context */ tlsdata->ssl_context = ctx = sslctx_client_setup(TLSv1_method(), tlsdata); if (!ctx) { snmp_log(LOG_ERR, "failed to create TLS context\n"); return NULL; } /* RFC5953 Section 5.3.1: Establishing a Session as a Client 3) Using the destTransportDomain and destTransportAddress values, the client will initiate the (D)TLS handshake protocol to establish session keys for message integrity and encryption. */ /* Implementation note: The transport domain and address are pre-processed by this point */ /* Create a BIO connection for it */ DEBUGMSGTL(("tlstcp", "connecting to tlstcp %s\n", tlsdata->addr_string)); t->remote = (void *) strdup(tlsdata->addr_string); t->remote_length = strlen(tlsdata->addr_string) + 1; bio = BIO_new_connect(tlsdata->addr_string); /* RFC5953 Section 5.3.1: Establishing a Session as a Client 3) continued: If the attempt to establish a session is unsuccessful, then snmpTlstmSessionOpenErrors is incremented, an error indication is returned, and processing stops. */ if (NULL == bio) { snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS); snmp_log(LOG_ERR, "tlstcp: failed to create bio\n"); _openssl_log_error(rc, NULL, "BIO creation"); return NULL; } /* Tell the BIO to actually do the connection */ if ((rc = BIO_do_connect(bio)) <= 0) { snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS); snmp_log(LOG_ERR, "tlstcp: failed to connect to %s\n", tlsdata->addr_string); _openssl_log_error(rc, NULL, "BIO_do_connect"); BIO_free(bio); return NULL; } /* Create the SSL layer on top of the socket bio */ ssl = tlsdata->ssl = SSL_new(ctx); if (NULL == ssl) { snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS); snmp_log(LOG_ERR, "tlstcp: failed to create a SSL connection\n"); BIO_free(bio); return NULL; } /* Bind the SSL layer to the BIO */ SSL_set_bio(ssl, bio, bio); SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); verify_info = SNMP_MALLOC_TYPEDEF(_netsnmp_verify_info); if (NULL == verify_info) { snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS); snmp_log(LOG_ERR, "tlstcp: failed to create a SSL connection\n"); SSL_shutdown(ssl); BIO_free(bio); return NULL; } SSL_set_ex_data(ssl, tls_get_verify_info_index(), verify_info); /* Then have SSL do it's connection over the BIO */ if ((rc = SSL_connect(ssl)) <= 0) { snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS); snmp_log(LOG_ERR, "tlstcp: failed to ssl_connect\n"); BIO_free(bio); return NULL; } /* RFC5953 Section 5.3.1: Establishing a Session as a Client 3) continued: If the session failed to open because the presented server certificate was unknown or invalid then the snmpTlstmSessionUnknownServerCertificate or snmpTlstmSessionInvalidServerCertificates MUST be incremented and a snmpTlstmServerCertificateUnknown or snmpTlstmServerInvalidCertificate notification SHOULD be sent as appropriate. Reasons for server certificate invalidation includes, but is not limited to, cryptographic validation failures and an unexpected presented certificate identity. */ /* RFC5953 Section 5.3.1: Establishing a Session as a Client 4) The (D)TLS client MUST then verify that the (D)TLS server's presented certificate is the expected certificate. The (D)TLS client MUST NOT transmit SNMP messages until the server certificate has been authenticated, the client certificate has been transmitted and the TLS connection has been fully established. If the connection is being established from configuration based on SNMP-TARGET-MIB configuration, then the snmpTlstmAddrTable DESCRIPTION clause describes how the verification is done (using either a certificate fingerprint, or an identity authenticated via certification path validation). If the connection is being established for reasons other than configuration found in the SNMP-TARGET-MIB then configuration and procedures outside the scope of this document should be followed. Configuration mechanisms SHOULD be similar in nature to those defined in the snmpTlstmAddrTable to ensure consistency across management configuration systems. For example, a command-line tool for generating SNMP GETs might support specifying either the server's certificate fingerprint or the expected host name as a command line argument. */ /* Implementation notes: - All remote certificate fingerprints are expected to be stored in the transport's config information. This is true both for CLI clients and TARGET-MIB sessions. - netsnmp_tlsbase_verify_server_cert implements these checks */ if (netsnmp_tlsbase_verify_server_cert(ssl, tlsdata) != SNMPERR_SUCCESS) { /* XXX: unknown vs invalid; two counters */ snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONUNKNOWNSERVERCERTIFICATE); snmp_log(LOG_ERR, "tlstcp: failed to verify ssl certificate\n"); SSL_shutdown(ssl); BIO_free(bio); return NULL; } /* RFC5953 Section 5.3.1: Establishing a Session as a Client 5) (D)TLS provides assurance that the authenticated identity has been signed by a trusted configured certification authority. If verification of the server's certificate fails in any way (for example because of failures in cryptographic verification or the presented identity did not match the expected named entity) then the session establishment MUST fail, the snmpTlstmSessionInvalidServerCertificates object is incremented. If the session can not be opened for any reason at all, including cryptographic verification failures, then the snmpTlstmSessionOpenErrors counter is incremented and processing stops. */ /* XXX: add snmpTlstmSessionInvalidServerCertificates on crypto failure */ /* RFC5953 Section 5.3.1: Establishing a Session as a Client 6) The TLSTM-specific session identifier (tlstmSessionID) is set in the tmSessionID of the tmStateReference passed to the TLS Transport Model to indicate that the session has been established successfully and to point to a specific (D)TLS connection for future use. The tlstmSessionID is also stored in the LCD for later lookup during processing of incoming messages (Section 5.1.2). */ /* Implementation notes: - the tlsdata pointer is used as our session identifier, as noted in the netsnmp_tlstcp_recv() function comments. */ t->sock = BIO_get_fd(bio, NULL); } else { #ifndef NETSNMP_NO_LISTEN_SUPPORT /* Is the server */ /* Create the socket bio */ DEBUGMSGTL(("tlstcp", "listening on tlstcp port %s\n", tlsdata->addr_string)); tlsdata->accept_bio = BIO_new_accept(tlsdata->addr_string); t->local = (void *) strdup(tlsdata->addr_string); t->local_length = strlen(tlsdata->addr_string)+1; if (NULL == tlsdata->accept_bio) { snmp_log(LOG_ERR, "TLSTCP: Falied to create a accept BIO\n"); return NULL; } /* openssl requires an initial accept to bind() the socket */ if (BIO_do_accept(tlsdata->accept_bio) <= 0) { _openssl_log_error(rc, tlsdata->ssl, "BIO_do__accept"); snmp_log(LOG_ERR, "TLSTCP: Falied to do first accept on the TLS accept BIO\n"); return NULL; } /* create the OpenSSL TLS context */ tlsdata->ssl_context = sslctx_server_setup(TLSv1_method()); t->sock = BIO_get_fd(tlsdata->accept_bio, NULL); t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN; #else /* NETSNMP_NO_LISTEN_SUPPORT */ return NULL; #endif /* NETSNMP_NO_LISTEN_SUPPORT */ } return t; }
LWS_VISIBLE int lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n, m; #ifndef USE_WOLFSSL BIO *bio; #endif if (!LWS_SSL_ENABLED(context)) return 0; switch (wsi->mode) { case LWSCM_SSL_INIT: wsi->ssl = SSL_new(context->ssl_ctx); if (wsi->ssl == NULL) { lwsl_err("SSL_new failed: %s\n", ERR_error_string(SSL_get_error(wsi->ssl, 0), NULL)); lws_decode_ssl_error(); if (accept_fd != LWS_SOCK_INVALID) compatible_close(accept_fd); goto fail; } SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, context); SSL_set_fd(wsi->ssl, accept_fd); #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->ssl, 1); #else wolfSSL_set_using_nonblock(wsi->ssl, 1); #endif #else SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); bio = SSL_get_rbio(wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #endif /* * we are not accepted yet, but we need to enter ourselves * as a live connection. That way we can retry when more * pieces come if we're not sorted yet */ wsi->mode = LWSCM_SSL_ACK_PENDING; if (insert_wsi_socket_into_fds(context, wsi)) goto fail; lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, context->timeout_secs); lwsl_info("inserted SSL accept into fds, trying SSL_accept\n"); /* fallthru */ case LWSCM_SSL_ACK_PENDING: if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) goto fail; lws_latency_pre(context, wsi); n = recv(wsi->sock, (char *)pt->serv_buf, LWS_MAX_SOCKET_IO_BUF, MSG_PEEK); /* * optionally allow non-SSL connect on SSL listening socket * This is disabled by default, if enabled it goes around any * SSL-level access control (eg, client-side certs) so leave * it disabled unless you know it's not a problem for you */ if (context->allow_non_ssl_on_ssl_port) { if (n >= 1 && pt->serv_buf[0] >= ' ') { /* * TLS content-type for Handshake is 0x16, and * for ChangeCipherSpec Record, it's 0x14 * * A non-ssl session will start with the HTTP * method in ASCII. If we see it's not a legit * SSL handshake kill the SSL for this * connection and try to handle as a HTTP * connection upgrade directly. */ wsi->use_ssl = 0; SSL_shutdown(wsi->ssl); SSL_free(wsi->ssl); wsi->ssl = NULL; if (lws_check_opt(context->options, LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS)) wsi->redirect_to_https = 1; goto accepted; } if (!n) /* * connection is gone, or nothing to read * if it's gone, we will timeout on * PENDING_TIMEOUT_SSL_ACCEPT */ break; if (n < 0 && (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK)) { /* * well, we get no way to know ssl or not * so go around again waiting for something * to come and give us a hint, or timeout the * connection. */ m = SSL_ERROR_WANT_READ; goto go_again; } } /* normal SSL connection processing path */ n = SSL_accept(wsi->ssl); lws_latency(context, wsi, "SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1); if (n == 1) goto accepted; m = SSL_get_error(wsi->ssl, n); lwsl_debug("SSL_accept failed %d / %s\n", m, ERR_error_string(m, NULL)); go_again: if (m == SSL_ERROR_WANT_READ) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) goto fail; lwsl_info("SSL_ERROR_WANT_READ\n"); break; } if (m == SSL_ERROR_WANT_WRITE) { if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) goto fail; break; } lwsl_debug("SSL_accept failed skt %u: %s\n", wsi->sock, ERR_error_string(m, NULL)); goto fail; accepted: /* OK, we are accepted... give him some time to negotiate */ lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, context->timeout_secs); wsi->mode = LWSCM_HTTP_SERVING; lws_http2_configure_if_upgraded(wsi); lwsl_debug("accepted new SSL conn\n"); break; } return 0; fail: return 1; }
static int netsnmp_tlstcp_accept(netsnmp_transport *t) { BIO *accepted_bio; int rc; SSL_CTX *ctx; SSL *ssl; _netsnmpTLSBaseData *tlsdata = NULL; DEBUGMSGTL(("tlstcp", "netsnmp_tlstcp_accept called\n")); tlsdata = (_netsnmpTLSBaseData *) t->data; rc = BIO_do_accept(tlsdata->accept_bio); if (rc <= 0) { snmp_log(LOG_ERR, "BIO_do_accept failed\n"); _openssl_log_error(rc, NULL, "BIO_do_accept"); /* XXX: need to close the listening connection here? */ return -1; } tlsdata->accepted_bio = accepted_bio = BIO_pop(tlsdata->accept_bio); if (!accepted_bio) { snmp_log(LOG_ERR, "Failed to pop an accepted bio off the bio staack\n"); /* XXX: need to close the listening connection here? */ return -1; } /* create the OpenSSL TLS context */ ctx = tlsdata->ssl_context; /* create the server's main SSL bio */ ssl = tlsdata->ssl = SSL_new(ctx); if (!tlsdata->ssl) { snmp_log(LOG_ERR, "TLSTCP: Failed to create a SSL BIO\n"); BIO_free(accepted_bio); tlsdata->accepted_bio = NULL; return -1; } SSL_set_bio(ssl, accepted_bio, accepted_bio); if ((rc = SSL_accept(ssl)) <= 0) { snmp_log(LOG_ERR, "TLSTCP: Failed SSL_accept\n"); _openssl_log_error(rc, ssl, "SSL_accept"); SSL_shutdown(tlsdata->ssl); SSL_free(tlsdata->ssl); tlsdata->accepted_bio = NULL; /* freed by SSL_free */ tlsdata->ssl = NULL; return -1; } /* * currently netsnmp_tlsbase_wrapup_recv is where we check for * algorithm compliance, but for tls we know the algorithms * at this point, so we could bail earlier... */ #if 0 /* moved checks to netsnmp_tlsbase_wrapup_recv */ netsnmp_openssl_null_checks(tlsdata->ssl, &no_auth, NULL); if (no_auth != 0) { /* null/unknown authentication */ /* xxx-rks: snmp_increment_statistic(STAT_???); */ snmp_log(LOG_ERR, "tlstcp: connection with NULL authentication\n"); SSL_shutdown(tlsdata->ssl); SSL_free(tlsdata->ssl); tlsdata->accepted_bio = NULL; /* freed by SSL_free */ tlsdata->ssl = NULL; return -1; } #endif /* RFC5953 Section 5.3.2: Accepting a Session as a Server A (D)TLS server should accept new session connections from any client that it is able to verify the client's credentials for. This is done by authenticating the client's presented certificate through a certificate path validation process (e.g. [RFC5280]) or through certificate fingerprint verification using fingerprints configured in the snmpTlstmCertToTSNTable. Afterward the server will determine the identity of the remote entity using the following procedures. The (D)TLS server identifies the authenticated identity from the (D)TLS client's principal certificate using configuration information from the snmpTlstmCertToTSNTable mapping table. The (D)TLS server MUST request and expect a certificate from the client and MUST NOT accept SNMP messages over the (D)TLS connection until the client has sent a certificate and it has been authenticated. The resulting derived tmSecurityName is recorded in the tmStateReference cache as tmSecurityName. The details of the lookup process are fully described in the DESCRIPTION clause of the snmpTlstmCertToTSNTable MIB object. If any verification fails in any way (for example because of failures in cryptographic verification or because of the lack of an appropriate row in the snmpTlstmCertToTSNTable) then the session establishment MUST fail, and the snmpTlstmSessionInvalidClientCertificates object is incremented. If the session can not be opened for any reason at all, including cryptographic verification failures, then the snmpTlstmSessionOpenErrors counter is incremented and processing stops. Servers that wish to support multiple principals at a particular port SHOULD make use of a (D)TLS extension that allows server-side principal selection like the Server Name Indication extension defined in Section 3.1 of [RFC4366]. Supporting this will allow, for example, sending notifications to a specific principal at a given TCP or UDP port. */ /* Implementation notes: - we expect fingerprints to be stored in the transport config - we do not currently support mulitple principals and only offer one */ if ((rc = netsnmp_tlsbase_verify_client_cert(ssl, tlsdata)) != SNMPERR_SUCCESS) { /* XXX: free needed memory */ snmp_log(LOG_ERR, "TLSTCP: Falied checking client certificate\n"); snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCLIENTCERTIFICATES); SSL_shutdown(tlsdata->ssl); SSL_free(tlsdata->ssl); tlsdata->accepted_bio = NULL; /* freed by SSL_free */ tlsdata->ssl = NULL; return -1; } /* XXX: check acceptance criteria here */ DEBUGMSGTL(("tlstcp", "accept succeeded on sock %d\n", t->sock)); /* RFC5953 Section 5.1.2 step 1, part2:: * If this is the first message received through this session and the session does not have an assigned tlstmSessionID yet then the snmpTlstmSessionAccepts counter is incremented and a tlstmSessionID for the session is created. This will only happen on the server side of a connection because a client would have already assigned a tlstmSessionID during the openSession() invocation. Implementations may have performed the procedures described in Section 5.3.2 prior to this point or they may perform them now, but the procedures described in Section 5.3.2 MUST be performed before continuing beyond this point. */ /* We're taking option 2 and incrementing the session accepts here rather than upon receiving the first packet */ snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONACCEPTS); /* XXX: check that it returns something so we can free stuff? */ return BIO_get_fd(tlsdata->accepted_bio, NULL); }
bool SSLSocket::waitWant(int ret, uint64_t millis) { #ifdef HEADER_OPENSSLV_H int err = SSL_get_error(ssl, ret); switch(err) { case SSL_ERROR_WANT_READ: return wait(millis, Socket::WAIT_READ) == WAIT_READ; case SSL_ERROR_WANT_WRITE: return wait(millis, Socket::WAIT_WRITE) == WAIT_WRITE; #else int err = ssl->last_error; switch(err) { case GNUTLS_E_INTERRUPTED: case GNUTLS_E_AGAIN: { int waitFor = wait(millis, Socket::WAIT_READ | Socket::WAIT_WRITE); return (waitFor & Socket::WAIT_READ) || (waitFor & Socket::WAIT_WRITE); } #endif // Check if this is a fatal error... default: checkSSL(ret); } dcdebug("SSL: Unexpected fallthrough"); // There was no error? return true; } int SSLSocket::read(void* aBuffer, int aBufLen) throw(SocketException) { if(!ssl) { return -1; } int len = checkSSL(SSL_read(ssl, aBuffer, aBufLen)); if(len > 0) { stats.totalDown += len; //dcdebug("In(s): %.*s\n", len, (char*)aBuffer); } return len; } int SSLSocket::write(const void* aBuffer, int aLen) throw(SocketException) { if(!ssl) { return -1; } int ret = checkSSL(SSL_write(ssl, aBuffer, aLen)); if(ret > 0) { stats.totalUp += ret; //dcdebug("Out(s): %.*s\n", ret, (char*)aBuffer); } return ret; } int SSLSocket::checkSSL(int ret) throw(SocketException) { if(!ssl) { return -1; } if(ret <= 0) { int err = SSL_get_error(ssl, ret); switch(err) { case SSL_ERROR_NONE: // Fallthrough - YaSSL doesn't for example return an openssl compatible error on recv fail case SSL_ERROR_WANT_READ: // Fallthrough case SSL_ERROR_WANT_WRITE: return -1; case SSL_ERROR_ZERO_RETURN: #ifndef HEADER_OPENSSLV_H if(ssl->last_error == GNUTLS_E_INTERRUPTED || ssl->last_error == GNUTLS_E_AGAIN) return -1; #endif throw SocketException(STRING(CONNECTION_CLOSED)); default: { ssl.reset(); // @todo replace 80 with MAX_ERROR_SZ or whatever's appropriate for yaSSL in some nice way... char errbuf[80]; /* TODO: better message for SSL_ERROR_SYSCALL * If the error queue is empty (i.e. ERR_get_error() returns 0), ret can be used to find out more about the error: * If ret == 0, an EOF was observed that violates the protocol. If ret == -1, the underlying BIO reported an I/O error * (for socket I/O on Unix systems, consult errno for details). */ int error = ERR_get_error(); sprintf(errbuf, "%s %d: %s", CSTRING(SSL_ERROR), err, (error == 0) ? CSTRING(CONNECTION_CLOSED) : ERR_reason_error_string(error)); throw SSLSocketException(errbuf); } } } return ret; } int SSLSocket::wait(uint64_t millis, int waitFor) throw(SocketException) { #ifdef HEADER_OPENSSLV_H if(ssl && (waitFor & Socket::WAIT_READ)) { /** @todo Take writing into account as well if reading is possible? */ char c; if(SSL_peek(ssl, &c, 1) > 0) return WAIT_READ; } #endif return Socket::wait(millis, waitFor); } bool SSLSocket::isTrusted() throw() { if(!ssl) { return false; } #ifdef HEADER_OPENSSLV_H if(SSL_get_verify_result(ssl) != X509_V_OK) { return false; } #else if(gnutls_certificate_verify_peers(((SSL*)ssl)->gnutls_state) != 0) { return false; } #endif X509* cert = SSL_get_peer_certificate(ssl); if(!cert) { return false; } X509_free(cert); return true; } std::string SSLSocket::getCipherName() throw() { if(!ssl) return Util::emptyString; return SSL_get_cipher_name(ssl); } std::string SSLSocket::getDigest() const throw() { #ifdef HEADER_OPENSSLV_H if(!ssl) return Util::emptyString; X509* x509 = SSL_get_peer_certificate(ssl); if(!x509) return Util::emptyString; return ssl::X509_digest(x509, EVP_sha1()); #else return Util::emptyString; #endif } void SSLSocket::shutdown() throw() { if(ssl) SSL_shutdown(ssl); } void SSLSocket::close() throw() { if(ssl) { ssl.reset(); } Socket::shutdown(); Socket::close(); } } // namespace dcpp
/*********************parent process tcp connection use to manage************************/ void client_mgr(char *ip, int serverPort, int pipefd, int pid) { int flag = 0; char *p; char name[256], passwd[256]; char realName[512]; int err, fd, i; struct sockaddr_in sa; char buf[4096]; SSL_CTX* ctx; SSL* ssl; //create a TCP socket fd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR(fd, "socket"); memset (&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(ip); sa.sin_port = htons(serverPort); //connect step err = connect(fd, (struct sockaddr*) &sa, sizeof(sa)); CHK_ERR(err, "connect"); sleep(2); puts("Please input the common name: "); scanf("%s", realName); setupCTX(&ctx); //build SSL on the TCP connection ssl = SSL_new(ctx); CHK_NULL(ssl); SSL_set_fd (ssl, fd); err = SSL_connect(ssl); CHK_SSL(err); //check certificate SSL_CTX_load_verify_locations(ctx, CACERT, NULL); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); int result = SSL_get_verify_result(ssl); if(result == X509_V_OK || result == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) { printf("The certificate is valid.\n"); } else { printf("Invalid certificate %d\n", result); exit(1); } X509* server_cert = SSL_get_peer_certificate(ssl); CHK_NULL(server_cert); char *str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0); CHK_NULL(str); OPENSSL_free(str); str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0); CHK_NULL(str); OPENSSL_free(str); X509_NAME *xname = X509_get_subject_name(server_cert); X509_NAME_get_text_by_NID(xname, NID_commonName, commonName, 512); if( strcasecmp(commonName, realName) !=0 ) { printf("commonName is wrong.\n"); exit(1); } printf("commonName is right.\n"); printf("Server authentication is successful.\n"); //release! X509_free(server_cert); sleep(2); while(!flag) { //handle the login part printf("username: "******"%s",name); getchar(); //safe mode set_disp_mode(STDIN_FILENO, 0); getpasswd(passwd, sizeof(passwd)); p = passwd; while(*p != '\n') p++; *p = '\0'; //OK! set_disp_mode(STDIN_FILENO, 1); sendName(ssl, name); sendPass(ssl, passwd); SSL_read(ssl, buf, sizeof(buf) - 1); putchar(10); if( buf[0] == 'o' ) { puts("Connect successfully"); flag = 1; } else { puts("wrong password, please try again!"); } } //clean the password for security reason memset(passwd, 0, sizeof(passwd)); genKey(key); sendKey(ssl, key); while (1) { talkToudp(key, pipefd, 'k'); printf("1. ipnut 'q' to quit.\n"); printf("2. input 'c' to change the key.\n"); scanf("%s", buf); if (strlen(buf) == 1) { if (buf[0]=='q') { break; } else if( buf[0]=='r'){ genKey(key); sendKey(ssl, key); } } else { printf("Invalid.\n"); continue; } } memset(key, 0, KEYSIZE); memset(IV, 0, IVSIZE); sendKey(ssl, key); sleep(1); kill(pid, SIGTERM); wait(0); SSL_shutdown(ssl); /* send SSL/TLS close_notify */ close(fd); SSL_free(ssl); SSL_CTX_free(ctx); }
static int amqp_ssl_socket_open(void *base, const char *host, int port, struct timeval *timeout) { struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; long result; int status; amqp_time_t deadline; X509 *cert; BIO *bio; if (-1 != self->sockfd) { return AMQP_STATUS_SOCKET_INUSE; } ERR_clear_error(); self->ssl = SSL_new(self->ctx); if (!self->ssl) { self->internal_error = ERR_peek_error(); status = AMQP_STATUS_SSL_ERROR; goto exit; } status = amqp_time_from_now(&deadline, timeout); if (AMQP_STATUS_OK != status) { return status; } self->sockfd = amqp_open_socket_inner(host, port, deadline); if (0 > self->sockfd) { status = self->sockfd; self->internal_error = amqp_os_socket_error(); self->sockfd = -1; goto error_out1; } bio = BIO_new(amqp_openssl_bio()); if (!bio) { status = AMQP_STATUS_NO_MEMORY; goto error_out2; } BIO_set_fd(bio, self->sockfd, BIO_NOCLOSE); SSL_set_bio(self->ssl, bio, bio); start_connect: status = SSL_connect(self->ssl); if (status != 1) { self->internal_error = SSL_get_error(self->ssl, status); switch (self->internal_error) { case SSL_ERROR_WANT_READ: status = amqp_poll(self->sockfd, AMQP_SF_POLLIN, deadline); break; case SSL_ERROR_WANT_WRITE: status = amqp_poll(self->sockfd, AMQP_SF_POLLOUT, deadline); break; default: status = AMQP_STATUS_SSL_CONNECTION_FAILED; } if (AMQP_STATUS_OK == status) { goto start_connect; } goto error_out2; } cert = SSL_get_peer_certificate(self->ssl); if (self->verify_peer) { if (!cert) { self->internal_error = 0; status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED; goto error_out3; } result = SSL_get_verify_result(self->ssl); if (X509_V_OK != result) { self->internal_error = result; status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED; goto error_out4; } } if (self->verify_hostname) { if (!cert) { self->internal_error = 0; status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED; goto error_out3; } if (AMQP_HVR_MATCH_FOUND != amqp_ssl_validate_hostname(host, cert)) { self->internal_error = 0; status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED; goto error_out4; } } X509_free(cert); self->internal_error = 0; status = AMQP_STATUS_OK; exit: return status; error_out4: X509_free(cert); error_out3: SSL_shutdown(self->ssl); error_out2: amqp_os_socket_close(self->sockfd); self->sockfd = -1; error_out1: SSL_free(self->ssl); self->ssl = NULL; goto exit; }
THREAD_RETURN CYASSL_THREAD server_test(void* args) { SOCKET_T sockfd = 0; SOCKET_T clientfd = 0; SSL_METHOD* method = 0; SSL_CTX* ctx = 0; SSL* ssl = 0; char msg[] = "I hear you fa shizzle!"; char input[80]; int idx; int ch; int version = SERVER_DEFAULT_VERSION; int doCliCertCheck = 1; int useAnyAddr = 0; word16 port = yasslPort; int usePsk = 0; int doDTLS = 0; int useNtruKey = 0; int nonBlocking = 0; int trackMemory = 0; int fewerPackets = 0; int pkCallbacks = 0; char* cipherList = NULL; char* verifyCert = (char*)cliCert; char* ourCert = (char*)svrCert; char* ourKey = (char*)svrKey; int argc = ((func_args*)args)->argc; char** argv = ((func_args*)args)->argv; #ifdef HAVE_SNI char* sniHostName = NULL; #endif #ifdef HAVE_OCSP int useOcsp = 0; char* ocspUrl = NULL; #endif ((func_args*)args)->return_code = -1; /* error state */ #ifdef NO_RSA verifyCert = (char*)cliEccCert; ourCert = (char*)eccCert; ourKey = (char*)eccKey; #endif (void)trackMemory; (void)pkCallbacks; while ((ch = mygetopt(argc, argv, "?dbstnNufPp:v:l:A:c:k:S:oO:")) != -1) { switch (ch) { case '?' : Usage(); exit(EXIT_SUCCESS); case 'd' : doCliCertCheck = 0; break; case 'b' : useAnyAddr = 1; break; case 's' : usePsk = 1; break; case 't' : #ifdef USE_CYASSL_MEMORY trackMemory = 1; #endif break; case 'n' : useNtruKey = 1; break; case 'u' : doDTLS = 1; break; case 'f' : fewerPackets = 1; break; case 'P' : #ifdef HAVE_PK_CALLBACKS pkCallbacks = 1; #endif break; case 'p' : port = (word16)atoi(myoptarg); #if !defined(NO_MAIN_DRIVER) || defined(USE_WINDOWS_API) if (port == 0) err_sys("port number cannot be 0"); #endif break; case 'v' : version = atoi(myoptarg); if (version < 0 || version > 3) { Usage(); exit(MY_EX_USAGE); } break; case 'l' : cipherList = myoptarg; break; case 'A' : verifyCert = myoptarg; break; case 'c' : ourCert = myoptarg; break; case 'k' : ourKey = myoptarg; break; case 'N': nonBlocking = 1; break; case 'S' : #ifdef HAVE_SNI sniHostName = myoptarg; #endif break; case 'o' : #ifdef HAVE_OCSP useOcsp = 1; #endif break; case 'O' : #ifdef HAVE_OCSP useOcsp = 1; ocspUrl = myoptarg; #endif break; default: Usage(); exit(MY_EX_USAGE); } } myoptind = 0; /* reset for test cases */ /* sort out DTLS versus TLS versions */ if (version == CLIENT_INVALID_VERSION) { if (doDTLS) version = CLIENT_DTLS_DEFAULT_VERSION; else version = CLIENT_DEFAULT_VERSION; } else { if (doDTLS) { if (version == 3) version = -2; else version = -1; } } #ifdef USE_CYASSL_MEMORY if (trackMemory) InitMemoryTracker(); #endif switch (version) { #ifndef NO_OLD_TLS case 0: method = SSLv3_server_method(); break; #ifndef NO_TLS case 1: method = TLSv1_server_method(); break; case 2: method = TLSv1_1_server_method(); break; #endif #endif #ifndef NO_TLS case 3: method = TLSv1_2_server_method(); break; #endif #ifdef CYASSL_DTLS case -1: method = DTLSv1_server_method(); break; case -2: method = DTLSv1_2_server_method(); break; #endif default: err_sys("Bad SSL version"); } if (method == NULL) err_sys("unable to get method"); ctx = SSL_CTX_new(method); if (ctx == NULL) err_sys("unable to get ctx"); if (cipherList) if (SSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS) err_sys("server can't set cipher list 1"); #ifdef CYASSL_LEANPSK usePsk = 1; #endif #if defined(NO_RSA) && !defined(HAVE_ECC) usePsk = 1; #endif if (fewerPackets) CyaSSL_CTX_set_group_messages(ctx); #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) SSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); #endif #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) if (!usePsk) { if (SSL_CTX_use_certificate_file(ctx, ourCert, SSL_FILETYPE_PEM) != SSL_SUCCESS) err_sys("can't load server cert file, check file and run from" " CyaSSL home dir"); } #endif #ifdef HAVE_NTRU if (useNtruKey) { if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ourKey) != SSL_SUCCESS) err_sys("can't load ntru key file, " "Please run from CyaSSL home dir"); } #endif #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) if (!useNtruKey && !usePsk) { if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM) != SSL_SUCCESS) err_sys("can't load server private key file, check file and run " "from CyaSSL home dir"); } #endif if (usePsk) { #ifndef NO_PSK SSL_CTX_set_psk_server_callback(ctx, my_psk_server_cb); SSL_CTX_use_psk_identity_hint(ctx, "cyassl server"); if (cipherList == NULL) { const char *defaultCipherList; #ifdef HAVE_NULL_CIPHER defaultCipherList = "PSK-NULL-SHA256"; #else defaultCipherList = "PSK-AES128-CBC-SHA256"; #endif if (SSL_CTX_set_cipher_list(ctx, defaultCipherList) != SSL_SUCCESS) err_sys("server can't set cipher list 2"); } #endif } #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) /* if not using PSK, verify peer with certs */ if (doCliCertCheck && usePsk == 0) { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0); if (SSL_CTX_load_verify_locations(ctx, verifyCert, 0) != SSL_SUCCESS) err_sys("can't load ca file, Please run from CyaSSL home dir"); } #endif #if defined(CYASSL_SNIFFER) && !defined(HAVE_NTRU) && !defined(HAVE_ECC) /* don't use EDH, can't sniff tmp keys */ if (cipherList == NULL) { if (SSL_CTX_set_cipher_list(ctx, "AES256-SHA256") != SSL_SUCCESS) err_sys("server can't set cipher list 3"); } #endif #ifdef HAVE_SNI if (sniHostName) if (CyaSSL_CTX_UseSNI(ctx, CYASSL_SNI_HOST_NAME, sniHostName, XSTRLEN(sniHostName)) != SSL_SUCCESS) err_sys("UseSNI failed"); #endif ssl = SSL_new(ctx); if (ssl == NULL) err_sys("unable to get SSL"); #ifdef HAVE_CRL CyaSSL_EnableCRL(ssl, 0); CyaSSL_LoadCRL(ssl, crlPemDir, SSL_FILETYPE_PEM, CYASSL_CRL_MONITOR | CYASSL_CRL_START_MON); CyaSSL_SetCRL_Cb(ssl, CRL_CallBack); #endif #ifdef HAVE_OCSP if (useOcsp) { if (ocspUrl != NULL) { CyaSSL_CTX_SetOCSP_OverrideURL(ctx, ocspUrl); CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE | CYASSL_OCSP_URL_OVERRIDE); } else CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE); } #endif #ifdef HAVE_PK_CALLBACKS if (pkCallbacks) SetupPkCallbacks(ctx, ssl); #endif tcp_accept(&sockfd, &clientfd, (func_args*)args, port, useAnyAddr, doDTLS); if (!doDTLS) CloseSocket(sockfd); SSL_set_fd(ssl, clientfd); if (usePsk == 0) { #if !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) CyaSSL_SetTmpDH_file(ssl, dhParam, SSL_FILETYPE_PEM); #elif !defined(NO_CERTS) SetDH(ssl); /* repick suites with DHE, higher priority than PSK */ #endif } #ifndef CYASSL_CALLBACKS if (nonBlocking) { CyaSSL_set_using_nonblock(ssl, 1); tcp_set_nonblocking(&clientfd); NonBlockingSSL_Accept(ssl); } else if (SSL_accept(ssl) != SSL_SUCCESS) { int err = SSL_get_error(ssl, 0); char buffer[CYASSL_MAX_ERROR_SZ]; printf("error = %d, %s\n", err, ERR_error_string(err, buffer)); err_sys("SSL_accept failed"); } #else NonBlockingSSL_Accept(ssl); #endif showPeer(ssl); idx = SSL_read(ssl, input, sizeof(input)-1); if (idx > 0) { input[idx] = 0; printf("Client message: %s\n", input); } else if (idx < 0) { int readErr = SSL_get_error(ssl, 0); if (readErr != SSL_ERROR_WANT_READ) err_sys("SSL_read failed"); } if (SSL_write(ssl, msg, sizeof(msg)) != sizeof(msg)) err_sys("SSL_write failed"); #if defined(CYASSL_MDK_SHELL) && defined(HAVE_MDK_RTX) os_dly_wait(500) ; #endif SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ctx); CloseSocket(clientfd); ((func_args*)args)->return_code = 0; #ifdef USE_CYASSL_MEMORY if (trackMemory) ShowMemoryTracker(); #endif /* USE_CYASSL_MEMORY */ return 0; }