📄 ssl.c
字号:
{ int ret; maybe_log_shutdown_state(p_sess); // This is a mess. Ideally, when we're the sender, we'd like to get to the // SSL_RECEIVED_SHUTDOWN state to get a cryptographic guarantee that the // peer received all the data and shut the connection down cleanly. It // doesn't matter hugely apart from logging, but it's a nagging detail. // Unfortunately, no FTP client I found was able to get sends into that // state, so the best we can do is issue SSL_shutdown but not check the // errors / returns. At least this enables the receiver to be sure of the // integrity of the send in terms of unwanted truncation. ret = SSL_shutdown(p_ssl); maybe_log_shutdown_state(p_sess); if (ret == 0) { ret = SSL_shutdown(p_ssl); maybe_log_shutdown_state(p_sess); if (ret != 1) { if (tunable_strict_ssl_write_shutdown) { success = 0; } maybe_log_shutdown_state(p_sess); maybe_log_ssl_error_state(p_sess, ret); } } else if (ret < 0) { if (tunable_strict_ssl_write_shutdown) { success = 0; } maybe_log_ssl_error_state(p_sess, ret); } SSL_free(p_ssl); p_sess->p_data_ssl = NULL; } return success;}intssl_accept(struct vsf_session* p_sess, int fd){ /* SECURITY: data SSL connections don't have any auth on them as part of the * protocol. If a client sends an unfortunately optional client cert then * we can check for a match between the control and data connections. */ SSL* p_ssl; if (p_sess->p_data_ssl != NULL) { die("p_data_ssl should be NULL."); } p_ssl = get_ssl(p_sess, fd); if (p_ssl == NULL) { return 0; } p_sess->p_data_ssl = p_ssl; setup_bio_callbacks(p_ssl); if (str_getlen(&p_sess->control_cert_digest) > 0) { static struct mystr data_cert_digest; if (!ssl_cert_digest(p_ssl, p_sess, &data_cert_digest)) { if (tunable_debug_ssl) { str_alloc_text(&debug_str, "Missing cert on data channel."); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } ssl_data_close(p_sess); return 0; } if (str_strcmp(&p_sess->control_cert_digest, &data_cert_digest)) { if (tunable_debug_ssl) { str_alloc_text(&debug_str, "DIFFERENT cert on data channel."); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } ssl_data_close(p_sess); return 0; } if (tunable_debug_ssl) { str_alloc_text(&debug_str, "Matching cert on data channel."); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } } return 1;}voidssl_comm_channel_init(struct vsf_session* p_sess){ const struct vsf_sysutil_socketpair_retval retval = vsf_sysutil_unix_stream_socketpair(); p_sess->ssl_consumer_fd = retval.socket_one; p_sess->ssl_slave_fd = retval.socket_two;}static SSL*get_ssl(struct vsf_session* p_sess, int fd){ SSL* p_ssl = SSL_new(p_sess->p_ssl_ctx); if (p_ssl == NULL) { if (tunable_debug_ssl) { str_alloc_text(&debug_str, "SSL_new failed"); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } return NULL; } if (!SSL_set_fd(p_ssl, fd)) { if (tunable_debug_ssl) { str_alloc_text(&debug_str, "SSL_set_fd failed"); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } SSL_free(p_ssl); return NULL; } if (SSL_accept(p_ssl) != 1) { const char* p_err = get_ssl_error(); if (tunable_debug_ssl) { str_alloc_text(&debug_str, "SSL_accept failed: "); str_append_text(&debug_str, p_err); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } die(p_err); SSL_free(p_ssl); return NULL; } if (tunable_debug_ssl) { const char* p_ssl_version = SSL_get_cipher_version(p_ssl); SSL_CIPHER* p_ssl_cipher = SSL_get_current_cipher(p_ssl); const char* p_cipher_name = SSL_CIPHER_get_name(p_ssl_cipher); int reused = SSL_session_reused(p_ssl); X509* p_ssl_cert = SSL_get_peer_certificate(p_ssl); str_alloc_text(&debug_str, "SSL version: "); str_append_text(&debug_str, p_ssl_version); str_append_text(&debug_str, ", SSL cipher: "); str_append_text(&debug_str, p_cipher_name); if (reused) { str_append_text(&debug_str, ", reused"); } else { str_append_text(&debug_str, ", not reused"); } if (p_ssl_cert != NULL) { str_append_text(&debug_str, ", CERT PRESENTED"); X509_free(p_ssl_cert); } else { str_append_text(&debug_str, ", no cert"); } vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } return p_ssl;}static intssl_session_init(struct vsf_session* p_sess){ SSL* p_ssl = get_ssl(p_sess, VSFTP_COMMAND_FD); if (p_ssl == NULL) { return 0; } p_sess->p_control_ssl = p_ssl; (void) ssl_cert_digest(p_ssl, p_sess, &p_sess->control_cert_digest); setup_bio_callbacks(p_ssl); return 1;}static intssl_cert_digest(SSL* p_ssl, struct vsf_session* p_sess, struct mystr* p_str){ X509* p_cert = SSL_get_peer_certificate(p_ssl); unsigned int num_bytes = 0; if (p_cert == NULL) { return 0; } str_reserve(p_str, EVP_MAX_MD_SIZE); str_empty(p_str); str_rpad(p_str, EVP_MAX_MD_SIZE); if (!X509_digest(p_cert, EVP_sha256(), (unsigned char*) str_getbuf(p_str), &num_bytes)) { die("X509_digest failed"); } X509_free(p_cert); if (tunable_debug_ssl) { unsigned int i; str_alloc_text(&debug_str, "Cert digest:"); for (i = 0; i < num_bytes; ++i) { str_append_char(&debug_str, ' '); str_append_ulong( &debug_str, (unsigned long) (unsigned char) str_get_char_at(p_str, i)); } vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } str_trunc(p_str, num_bytes); return 1;}static char*get_ssl_error(){ SSL_load_error_strings(); return ERR_error_string(ERR_get_error(), NULL);}static void setup_bio_callbacks(SSL* p_ssl){ BIO* p_bio = SSL_get_rbio(p_ssl); BIO_set_callback(p_bio, bio_callback); p_bio = SSL_get_wbio(p_ssl); BIO_set_callback(p_bio, bio_callback);}static longbio_callback( BIO* p_bio, int oper, const char* p_arg, int argi, long argl, long ret){ int retval = 0; int fd = 0; (void) p_arg; (void) argi; (void) argl; if (oper == (BIO_CB_READ | BIO_CB_RETURN) || oper == (BIO_CB_WRITE | BIO_CB_RETURN)) { retval = (int) ret; fd = BIO_get_fd(p_bio, NULL); } vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, fd); return ret;}static intssl_verify_callback(int verify_ok, X509_STORE_CTX* p_ctx){ (void) p_ctx; if (tunable_validate_cert) { return verify_ok; } return 1;}#else /* VSF_BUILD_SSL */voidssl_init(struct vsf_session* p_sess){ (void) p_sess; die("SSL: ssl_enable is set but SSL support not compiled in");}voidhandle_auth(struct vsf_session* p_sess){ (void) p_sess;}voidhandle_pbsz(struct vsf_session* p_sess){ (void) p_sess;}voidhandle_prot(struct vsf_session* p_sess){ (void) p_sess;}voidssl_getline(const struct vsf_session* p_sess, struct mystr* p_str, char end_char, char* p_buf, unsigned int buflen){ (void) p_sess; (void) p_str; (void) end_char; (void) p_buf; (void) buflen;}intssl_read(struct vsf_session* p_sess, char* p_buf, unsigned int len){ (void) p_sess; (void) p_buf; (void) len; return -1;}intssl_write(void* p_ssl, const char* p_buf, unsigned int len){ (void) p_ssl; (void) p_buf; (void) len; return -1;}intssl_write_str(void* p_ssl, const struct mystr* p_str){ (void) p_ssl; (void) p_str; return -1;}intssl_accept(struct vsf_session* p_sess, int fd){ (void) p_sess; (void) fd; return -1;}intssl_data_close(struct vsf_session* p_sess){ (void) p_sess; return 1;}voidssl_comm_channel_init(struct vsf_session* p_sess){ (void) p_sess;}#endif /* VSF_BUILD_SSL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -