bool SSLSocket::setupCrypto(SSLSocket *session /* = NULL */) { if (m_handle) { raise_warning("SSL/TLS already set-up for this stream"); return false; } /* need to do slightly different things, based on client/server method, * so lets remember which method was selected */ #if OPENSSL_VERSION_NUMBER < 0x00909000L SSL_METHOD *smethod; #else const SSL_METHOD *smethod; #endif switch (m_method) { case ClientSSLv23: m_client = true; smethod = SSLv23_client_method(); break; case ClientSSLv3: m_client = true; smethod = SSLv3_client_method(); break; case ClientTLS: m_client = true; smethod = TLSv1_client_method(); break; case ServerSSLv23: m_client = false; smethod = SSLv23_server_method(); break; case ServerSSLv3: m_client = false; smethod = SSLv3_server_method(); break; /* SSLv2 protocol might be disabled in the OpenSSL library */ #ifndef OPENSSL_NO_SSL2 case ClientSSLv2: m_client = true; smethod = SSLv2_client_method(); break; case ServerSSLv2: m_client = false; smethod = SSLv2_server_method(); break; #else case ClientSSLv2: case ServerSSLv2: raise_warning("OpenSSL library does not support SSL2 protocol"); return false; break; #endif case ServerTLS: m_client = false; smethod = TLSv1_server_method(); break; default: return false; } SSL_CTX *ctx = SSL_CTX_new(smethod); if (ctx == nullptr) { raise_warning("failed to create an SSL context"); return false; } SSL_CTX_set_options(ctx, SSL_OP_ALL); m_handle = createSSL(ctx); if (m_handle == nullptr) { raise_warning("failed to create an SSL handle"); SSL_CTX_free(ctx); return false; } if (!SSL_set_fd(m_handle, m_fd)) { handleError(0, true); } if (session) { SSL_copy_session_id(m_handle, session->m_handle); } return true; }
int SecureSocket::secureConnect(int socket) { createSSL(); // attach the socket descriptor SSL_set_fd(m_ssl->m_ssl, socket); LOG((CLOG_DEBUG2 "connecting secure socket")); int r = SSL_connect(m_ssl->m_ssl); static int retry; checkResult(r, retry); if (isFatal()) { LOG((CLOG_ERR "failed to connect secure socket")); return -1; } // If we should retry, not ready and return 0 if (retry > 0) { LOG((CLOG_DEBUG2 "retry connect secure socket")); m_secureReady = false; return 0; } // No error, set ready, process and return ok m_secureReady = true; if (verifyCertFingerprint()) { LOG((CLOG_INFO "connected to secure socket")); if (!showCertificate()) { disconnect(); return -1;// Cert fail, error } } else { LOG((CLOG_ERR "failed to verify server certificate fingerprint")); disconnect(); return -1; // Fingerprint failed, error } LOG((CLOG_DEBUG2 "connected secure socket")); const SSL_CIPHER* cipher = SSL_get_current_cipher(m_ssl->m_ssl); if(cipher != NULL) { char * cipherVersion = SSL_CIPHER_description(cipher, NULL, 0); if(cipherVersion != NULL) { LOG((CLOG_INFO "%s", cipherVersion)); OPENSSL_free(cipherVersion); } } return 1; }
int SecureSocket::secureConnect(int socket) { createSSL(); // attach the socket descriptor SSL_set_fd(m_ssl->m_ssl, socket); LOG((CLOG_DEBUG2 "connecting secure socket")); int r = SSL_connect(m_ssl->m_ssl); static int retry; checkResult(r, retry); if (isFatal()) { LOG((CLOG_ERR "failed to connect secure socket")); retry = 0; return -1; } // If we should retry, not ready and return 0 if (retry > 0) { LOG((CLOG_DEBUG2 "retry connect secure socket")); m_secureReady = false; ARCH->sleep(s_retryDelay); return 0; } retry = 0; // No error, set ready, process and return ok m_secureReady = true; if (verifyCertFingerprint()) { LOG((CLOG_INFO "connected to secure socket")); if (!showCertificate()) { disconnect(); return -1;// Cert fail, error } } else { LOG((CLOG_ERR "failed to verify server certificate fingerprint")); disconnect(); return -1; // Fingerprint failed, error } LOG((CLOG_DEBUG2 "connected secure socket")); if (CLOG->getFilter() >= kDEBUG1) { showSecureCipherInfo(); } showSecureConnectInfo(); return 1; }
int SecureSocket::secureAccept(int socket) { createSSL(); // set connection socket to SSL state SSL_set_fd(m_ssl->m_ssl, socket); LOG((CLOG_DEBUG2 "accepting secure socket")); int r = SSL_accept(m_ssl->m_ssl); static int retry; checkResult(r, retry); if (isFatal()) { // tell user and sleep so the socket isn't hammered. LOG((CLOG_ERR "failed to accept secure socket")); LOG((CLOG_INFO "client connection may not be secure")); m_secureReady = false; ARCH->sleep(1); return -1; // Failed, error out } // If not fatal and no retry, state is good if (retry == 0) { m_secureReady = true; LOG((CLOG_INFO "accepted secure socket")); const SSL_CIPHER* cipher = SSL_get_current_cipher(m_ssl->m_ssl); if(cipher != NULL) { char * cipherVersion = SSL_CIPHER_description(cipher, NULL, 0); if(cipherVersion != NULL) { LOG((CLOG_INFO "%s", cipherVersion)); OPENSSL_free(cipherVersion); } } return 1; } // If not fatal and retry is set, not ready, and return retry if (retry > 0) { LOG((CLOG_DEBUG2 "retry accepting secure socket")); m_secureReady = false; return 0; } // no good state exists here LOG((CLOG_ERR "unexpected state attempting to accept connection")); return -1; }
int SecureSocket::secureAccept(int socket) { createSSL(); // set connection socket to SSL state SSL_set_fd(m_ssl->m_ssl, socket); LOG((CLOG_DEBUG2 "accepting secure socket")); int r = SSL_accept(m_ssl->m_ssl); static int retry; checkResult(r, retry); if (isFatal()) { // tell user and sleep so the socket isn't hammered. LOG((CLOG_ERR "failed to accept secure socket")); LOG((CLOG_INFO "client connection may not be secure")); m_secureReady = false; ARCH->sleep(1); retry = 0; return -1; // Failed, error out } // If not fatal and no retry, state is good if (retry == 0) { m_secureReady = true; LOG((CLOG_INFO "accepted secure socket")); if (CLOG->getFilter() >= kDEBUG1) { showSecureCipherInfo(); } showSecureConnectInfo(); return 1; } // If not fatal and retry is set, not ready, and return retry if (retry > 0) { LOG((CLOG_DEBUG2 "retry accepting secure socket")); m_secureReady = false; ARCH->sleep(s_retryDelay); return 0; } // no good state exists here LOG((CLOG_ERR "unexpected state attempting to accept connection")); return -1; }
int main(int argc, char *argv[]) { if(argc == 1) { fprintf(stderr,"Error no arguments type -? for usage.\n"); exit(EXIT_FAILURE); } int sockfd; SSL_CTX *ctx; //setup variables that define what the client does char request[LENGTH]; memset(request, '\0', LENGTH); enum { SEND_MODE, FETCH_MODE, VOUCH_MODE, LIST_MODE, DEFAULT_MODE } mode = DEFAULT_MODE; int option = 0; int circumference = 0, port = 0; char *fileName, *hostname, *trustedname, *certificate, *certname, *msg; //Specifying the expected options while ((option = getopt(argc, argv,"a:c:f:h:ln:u:v:?")) != -1) { switch (option) { case 'a' : //upload a file fileName = optarg; //print the request to a variable that will be send later snprintf(request, sizeof(request), "add file %s", basename(fileName)); //set the mode of the client mode = SEND_MODE; break; case 'c' : //provide circumference circumference = atoi(optarg); break; case 'f' : //fetch a file snprintf(request, sizeof(request), "fetch %s",optarg); fileName = optarg; mode = FETCH_MODE; break; case 'h' : //specify server address //get the hostname and port hostname = strtok(optarg, ":"); char *temp = strtok(NULL, ":"); if(temp != NULL) port = atoi(temp); break; case 'l' : //list all files on server snprintf(request, sizeof(request), "list"); mode = LIST_MODE; break; case 'n' : //require name in circle trustedname = optarg; break; case 'u' : //upload a cert fileName = optarg; certname = basename(fileName); snprintf(request, sizeof(request), "add cert %s",certname); mode = SEND_MODE; break; case 'v' : //vouch if(argv[optind] == NULL || argv[optind][0] == '-') { //check whether certificate arg is given fprintf(stderr,"Please specify a certicate. Type -? for usage.\n"); exit(EXIT_FAILURE); } fileName = argv[optind]; certname = basename(fileName); snprintf(request, sizeof(request), "vouch %s %s",optarg, certname); mode = VOUCH_MODE; optind = optind+1; break; case '?' : //print usage print_usage(); exit(EXIT_SUCCESS); break; default: print_usage(); exit(EXIT_FAILURE); } } //no hostname specified if(hostname == NULL || port == 0) { fprintf(stderr, "[Client] Please specify a hostname and port, type -? for usage\n"); exit(EXIT_FAILURE); } //try and connect to the server if((sockfd = connectServer(hostname, port)) == -1) { fprintf(stderr, "[Client] Unable to connect to the server.\n"); exit(EXIT_FAILURE); } //SSL handshake SSL *ssl = createSSL(sockfd, ctx); //ask the server to server us sendRequest(ssl, request); int getMsg = 1; //whether or not we want to get a message from the server after all is said and done int result; //execute the requested client options switch (mode) { case SEND_MODE : result = sendFile(ssl, fileName); if(result == EXIT_FAILURE) { exit(EXIT_FAILURE); } break; case FETCH_MODE : //first send circumference then send trustedname sendCircumference(ssl, circumference); memset(request, '\0', LENGTH); //empty the request buffer, ready to send trustedname snprintf(request, sizeof(request), "%s",trustedname); sendRequest(ssl, request); //send the trustedname as a request (only doing this because I cant be bothered writing a new method and this one works fine. if(getServerMessage(ssl) == EXIT_FAILURE) { exit(EXIT_FAILURE); } result = receiveFile(ssl); break; case LIST_MODE : result = receiveFile(ssl); break; case VOUCH_MODE : if(getServerMessage(ssl) == EXIT_FAILURE) { getMsg = 0; break; } result = sendFile(ssl, fileName);//send the vouching cert to the server if(result == EXIT_FAILURE) exit(EXIT_FAILURE); break; case DEFAULT_MODE: fprintf(stderr, "[Client] Please specify a send or receive argument, type -? for usage.\n"); exit(EXIT_FAILURE); } //get the result of our request back from the server if(getMsg) getServerMessage(ssl); close(sockfd); SSL_CTX_free(ctx); /* release context */ fprintf(stderr,"[Client] Connection lost.\n"); exit(EXIT_SUCCESS); }