/* Return -1 on error, 0 or success. */ int ssl_connect(struct socket *socket) { int ret; unsigned char *server_name; struct connection *conn = (struct connection *)socket->conn; /* TODO: Recode server_name to UTF-8. */ server_name = get_uri_string(conn->proxied_uri, URI_HOST); if (!server_name) { socket->ops->done(socket, connection_state(S_OUT_OF_MEM)); return -1; } /* RFC 3546 says literal IPv4 and IPv6 addresses are not allowed. */ if (is_ip_address(server_name, strlen((const char *)server_name))) mem_free_set(&server_name, NULL); if (init_ssl_connection(socket, server_name) == S_SSL_ERROR) { mem_free_if(server_name); socket->ops->done(socket, connection_state(S_SSL_ERROR)); return -1; } mem_free_if(server_name); if (socket->no_tls) ssl_set_no_tls(socket); #ifdef USE_OPENSSL SSL_set_fd((SSL *)socket->ssl, socket->fd); if (get_opt_bool((const unsigned char *)"connection.ssl.cert_verify", NULL)) SSL_set_verify((SSL *)socket->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); if (get_opt_bool((const unsigned char *)"connection.ssl.client_cert.enable", NULL)) { unsigned char *client_cert; #ifdef CONFIG_NSS_COMPAT_OSSL client_cert = get_opt_str( (const unsigned char *)"connection.ssl.client_cert.nickname", NULL); #else client_cert = get_opt_str( (const unsigned char *)"connection.ssl.client_cert.file", NULL); #endif if (!*client_cert) { client_cert = (unsigned char *)getenv("X509_CLIENT_CERT"); if (client_cert && !*client_cert) client_cert = NULL; } if (client_cert) { #ifdef CONFIG_NSS_COMPAT_OSSL SSL_CTX_use_certificate_chain_file( (SSL *) socket->ssl, (const char *)client_cert); #else SSL_CTX *ctx = ((SSL *) socket->ssl)->ctx; SSL_CTX_use_certificate_chain_file(ctx, (const char *)client_cert); SSL_CTX_use_PrivateKey_file(ctx, (const char *)client_cert, SSL_FILETYPE_PEM); #endif } } #elif defined(CONFIG_GNUTLS) /* GnuTLS uses function pointers for network I/O. The default * functions take a file descriptor, but it must be passed in * as a pointer. GnuTLS uses the GNUTLS_INT_TO_POINTER and * GNUTLS_POINTER_TO_INT macros for these conversions, but * those are unfortunately not in any public header. So * ELinks must just cast the pointer the best it can and hope * that the conversions match. */ gnutls_transport_set_ptr(*((ssl_t *) socket->ssl), (gnutls_transport_ptr_t) (longptr_T) socket->fd); /* TODO: Some certificates fuss. --pasky */ #endif ret = ssl_do_connect(socket); switch (ret) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ2: socket->ops->set_state(socket, connection_state(S_SSL_NEG)); set_handlers(socket->fd, (select_handler_T) ssl_want_read, NULL, (select_handler_T) dns_exception, socket); return -1; case SSL_ERROR_NONE: #ifdef CONFIG_GNUTLS if (!get_opt_bool((const unsigned char *)"connection.ssl.cert_verify", NULL)) break; if (!verify_certificates(socket)) #endif break; default: if (ret != SSL_ERROR_NONE) { /* DBG("sslerr %s", gnutls_strerror(ret)); */ socket->no_tls = !socket->no_tls; } connect_socket(socket, connection_state(S_SSL_ERROR)); return -1; } return 0; }
/* * Initialize SSL sub module * * Arguments: None * Returns: None */ void initSSL(void) { static void *ssl_API[ssl_API_pointers]; PyObject *ssl_api_object; PyObject *module; SSL_library_init(); ERR_load_SSL_strings(); import_crypto(); if ((module = Py_InitModule3("SSL", ssl_methods, ssl_doc)) == NULL) { return; } /* Initialize the C API pointer array */ ssl_API[ssl_Context_New_NUM] = (void *)ssl_Context_New; ssl_API[ssl_Connection_New_NUM] = (void *)ssl_Connection_New; ssl_api_object = PyCObject_FromVoidPtr((void *)ssl_API, NULL); if (ssl_api_object != NULL) PyModule_AddObject(module, "_C_API", ssl_api_object); /* Exceptions */ /* * ADD_EXCEPTION(dict,name,base) expands to a correct Exception declaration, * inserting OpenSSL.SSL.name into dict, derviving the exception from base. */ #define ADD_EXCEPTION(_name, _base) \ do { \ ssl_##_name = PyErr_NewException("OpenSSL.SSL."#_name, _base, NULL);\ if (ssl_##_name == NULL) \ goto error; \ if (PyModule_AddObject(module, #_name, ssl_##_name) != 0) \ goto error; \ } while (0) ssl_Error = PyErr_NewException("OpenSSL.SSL.Error", NULL, NULL); if (ssl_Error == NULL) goto error; if (PyModule_AddObject(module, "Error", ssl_Error) != 0) goto error; ADD_EXCEPTION(ZeroReturnError, ssl_Error); ADD_EXCEPTION(WantReadError, ssl_Error); ADD_EXCEPTION(WantWriteError, ssl_Error); ADD_EXCEPTION(WantX509LookupError, ssl_Error); ADD_EXCEPTION(SysCallError, ssl_Error); #undef ADD_EXCEPTION /* Method constants */ PyModule_AddIntConstant(module, "SSLv2_METHOD", ssl_SSLv2_METHOD); PyModule_AddIntConstant(module, "SSLv3_METHOD", ssl_SSLv3_METHOD); PyModule_AddIntConstant(module, "SSLv23_METHOD", ssl_SSLv23_METHOD); PyModule_AddIntConstant(module, "TLSv1_METHOD", ssl_TLSv1_METHOD); /* Verify constants */ PyModule_AddIntConstant(module, "VERIFY_NONE", SSL_VERIFY_NONE); PyModule_AddIntConstant(module, "VERIFY_PEER", SSL_VERIFY_PEER); PyModule_AddIntConstant(module, "VERIFY_FAIL_IF_NO_PEER_CERT", SSL_VERIFY_FAIL_IF_NO_PEER_CERT); PyModule_AddIntConstant(module, "VERIFY_CLIENT_ONCE", SSL_VERIFY_CLIENT_ONCE); /* File type constants */ PyModule_AddIntConstant(module, "FILETYPE_PEM", SSL_FILETYPE_PEM); PyModule_AddIntConstant(module, "FILETYPE_ASN1", SSL_FILETYPE_ASN1); /* SSL option constants */ PyModule_AddIntConstant(module, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); PyModule_AddIntConstant(module, "OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA); PyModule_AddIntConstant(module, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); PyModule_AddIntConstant(module, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); PyModule_AddIntConstant(module, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); /* More SSL option constants */ PyModule_AddIntConstant(module, "OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG); PyModule_AddIntConstant(module, "OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG); PyModule_AddIntConstant(module, "OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); PyModule_AddIntConstant(module, "OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG); PyModule_AddIntConstant(module, "OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); PyModule_AddIntConstant(module, "OP_MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING); PyModule_AddIntConstant(module, "OP_SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG); PyModule_AddIntConstant(module, "OP_TLS_D5_BUG", SSL_OP_TLS_D5_BUG); PyModule_AddIntConstant(module, "OP_TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG); PyModule_AddIntConstant(module, "OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); PyModule_AddIntConstant(module, "OP_ALL", SSL_OP_ALL); PyModule_AddIntConstant(module, "OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE); PyModule_AddIntConstant(module, "OP_TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG); PyModule_AddIntConstant(module, "OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1); PyModule_AddIntConstant(module, "OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2); PyModule_AddIntConstant(module, "OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG); PyModule_AddIntConstant(module, "OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); /* DTLS related options. The first two of these were introduced in * 2005, the third in 2007. To accomodate systems which are still using * older versions, make them optional. */ #ifdef SSL_OP_NO_QUERY_MTU PyModule_AddIntConstant(module, "OP_NO_QUERY_MTU", SSL_OP_NO_QUERY_MTU); #endif #ifdef SSL_OP_COOKIE_EXCHANGE PyModule_AddIntConstant(module, "OP_COOKIE_EXCHANGE", SSL_OP_COOKIE_EXCHANGE); #endif #ifdef SSL_OP_NO_TICKET PyModule_AddIntConstant(module, "OP_NO_TICKET", SSL_OP_NO_TICKET); #endif /* For SSL_set_shutdown */ PyModule_AddIntConstant(module, "SENT_SHUTDOWN", SSL_SENT_SHUTDOWN); PyModule_AddIntConstant(module, "RECEIVED_SHUTDOWN", SSL_RECEIVED_SHUTDOWN); if (!init_ssl_context(module)) goto error; if (!init_ssl_connection(module)) goto error; #ifdef WITH_THREAD /* * Initialize this module's threading support structures. */ _pyOpenSSL_tstate_key = PyThread_create_key(); #endif error: ; }
int dtls_get_data (int s, SSL_CTX *ctx) { char *buf = NULL; fd_set readfds; int ret = 1, width = 0; int i = 0; SSL *con = NULL; BIO *sbio = NULL; int bufsize = BUFSIZ; bio_err = BIO_new_fp (stderr, BIO_NOCLOSE); bio_s_out = BIO_new_fp (stderr, BIO_NOCLOSE); if ((buf = OPENSSL_malloc (bufsize)) == NULL) { BIO_printf (bio_err, "out of memory\n"); goto ERR; } if (con == NULL) { con = SSL_new(ctx); } SSL_clear (con); if (SSL_version (con) == DTLS1_VERSION) { struct timeval timeout; sbio = BIO_new_dgram (s, BIO_NOCLOSE); timeout.tv_sec = 5; timeout.tv_usec = 0; BIO_ctrl (sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); timeout.tv_sec = 5; timeout.tv_usec = 0; BIO_ctrl (sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); /* want to do MTU discovery */ BIO_ctrl (sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); /* turn on cookie exchange */ SSL_set_options (con, SSL_OP_COOKIE_EXCHANGE); // fprintf (stderr, "%s: %s(): DTLSv1 Initialization done\n", __FILE__, __func__); } SSL_set_bio (con, sbio, sbio); SSL_set_accept_state (con); /* SSL_set_fd(con,s); */ width = s + 1; for (;;) { int read_from_terminal; int read_from_sslcon; read_from_terminal = 0; read_from_sslcon = SSL_pending (con); if (!read_from_sslcon) { struct timeval tv; FD_ZERO(&readfds); FD_SET(s, &readfds); tv.tv_sec = 1; tv.tv_usec = 0; i = select(width, (void *)&readfds, NULL, NULL, &tv); if (i < 0) { continue; } if (FD_ISSET (s, &readfds)) { read_from_sslcon = 1; } else { ret = 2; goto shut; } } if (read_from_sslcon) { if (!SSL_is_init_finished(con)) { i = init_ssl_connection(con); if (i < 0) { ret = 0; goto ERR; } else if (i == 0) { ret = 1; goto ERR; } } else { AGAIN: i = SSL_read (con, (char *) buf, bufsize); switch (SSL_get_error (con, i)) { case SSL_ERROR_NONE: write (fileno (stdout), buf, (unsigned int) i); if (SSL_pending(con)) { fprintf (stderr, "%s: %s(): Some more seems to be coming... "\ "letz wait for that\n", __FILE__, __func__); goto AGAIN; } else fprintf (stderr, "%s(): Hey, itz all over boss... do finishing "\ "ceremony\n", __func__); ret = 0; goto ERR; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_s_out,"Read BLOCK\n"); break; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: BIO_printf(bio_s_out,"ERROR\n"); ERR_print_errors(bio_err); ret = 1; goto ERR; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_s_out,"\nDONE\n"); ret = 0; goto ERR; } } } } ERR: if (0 == ret) { char temp [] = "ACK from SERVER: READ SUCCESSFULLY DONE\n"; for (;;) { i = SSL_write (con, temp, strlen (temp)); switch (SSL_get_error (con, i)) { case SSL_ERROR_NONE: if (SSL_pending (con)) break; else goto WRITEDONE; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf (bio_s_out, "Write BLOCK\n"); break; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: BIO_printf (bio_s_out, "ERROR\n"); ERR_print_errors (bio_err); ret = 1; goto WRITEDONE; case SSL_ERROR_ZERO_RETURN: BIO_printf (bio_s_out, "\nDONE\n"); ret = 1; goto WRITEDONE; } } } WRITEDONE: #ifdef DEBUG BIO_printf (bio_s_out, "shutting down SSL\n"); print_stats (bio_s_out, ctx); #endif #if 1 SSL_set_shutdown (con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(con); #endif shut: if (con != NULL) SSL_free (con); if (2 != ret) BIO_printf(bio_s_out,"CONNECTION CLOSED\n"); if (buf != NULL) { OPENSSL_cleanse (buf, bufsize); OPENSSL_free (buf); } if ((ret >= 0) && (2 != ret)) BIO_printf (bio_s_out, "ACCEPT\n"); return(ret); }