/** * Accept the GSI Authentication. * @param sock the socket for communication. * @param ctx the authorization context. * @return the context identifier. */ bool GSISocketServer::AcceptGSIAuthentication() { char *name = NULL; long errorcode = 0; int flags; time_t curtime, starttime; int ret, accept_status; bool accept_timed_out = false; int expected = 0; BIO *bio = NULL; char *cert_file, *user_cert, *user_key, *user_proxy; char *serial=NULL; cert_file = user_cert = user_key = user_proxy = NULL; if (proxy_get_filenames(0, &cert_file, &cacertdir, &user_proxy, &user_cert, &user_key) == 0) { (void)load_credentials(user_cert, user_key, &ucert, &own_stack, &upkey, NULL); } free(cert_file); free(user_cert); free(user_key); free(user_proxy); own_cert = ucert; own_key = upkey; ctx = SSL_CTX_new(SSLv23_method()); SSL_CTX_load_verify_locations(ctx, NULL, cacertdir); SSL_CTX_use_certificate(ctx, ucert); SSL_CTX_use_PrivateKey(ctx,upkey); SSL_CTX_set_cipher_list(ctx, "ALL:!LOW:!EXP:!MD5:!MD2"); SSL_CTX_set_purpose(ctx, X509_PURPOSE_ANY); SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, proxy_verify_callback); SSL_CTX_set_verify_depth(ctx, 100); SSL_CTX_set_cert_verify_callback(ctx, proxy_app_verify_callback, 0); if (own_stack) { /* * Certificate was a proxy with a cert. chain. * Add the certificates one by one to the chain. */ X509_STORE_add_cert(ctx->cert_store, ucert); for (int i = 0; i <sk_X509_num(own_stack); ++i) { X509 *cert = (sk_X509_value(own_stack,i)); if (!X509_STORE_add_cert(ctx->cert_store, cert)) { if (ERR_GET_REASON(ERR_peek_error()) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { ERR_clear_error(); continue; } else { SetErrorOpenSSL("Cannot add certificate to the SSL context's certificate store"); goto err; } } } } flags = fcntl(newsock, F_GETFL, 0); (void)fcntl(newsock, F_SETFL, flags | O_NONBLOCK); bio = BIO_new_socket(newsock, BIO_NOCLOSE); (void)BIO_set_nbio(bio, 1); ssl = SSL_new(ctx); setup_SSL_proxy_handler(ssl, cacertdir); writeb = bio->method->bwrite; readb = bio->method->bread; bio->method->bwrite = globusf_write; bio->method->bread = globusf_read; SSL_set_bio(ssl, bio, bio); curtime = starttime = time(NULL); ret = accept_status = -1; expected = 0; do { ret = do_select(newsock, starttime, timeout, expected); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Select status: %d",ret); curtime = time(NULL); if (ret == 0){ LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Select timed out."); if (curtime - starttime > timeout){ accept_timed_out = true; break; }else{ continue; } } if (ret > 0) { accept_status = SSL_accept(ssl); curtime = time(NULL); expected = errorcode = SSL_get_error(ssl, accept_status); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Accept status: %d",accept_status); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Error code: %d",errorcode); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "SSL_WANT_READ: %d, SSL_WANT_WRITE: %d",SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE); } if (ret < 0) // No more data from the select break; if (accept_status == 1) // SSL handshake completed break; if (timeout != -1 && (curtime - starttime > timeout)){ // Timeout reached accept_timed_out = true; break; } if (accept_status <= 0 && ( errorcode != SSL_ERROR_WANT_READ && errorcode != SSL_ERROR_WANT_WRITE )) // SSL handshake error break; } while (true); // Error enstabilishing context if (accept_status != 1){ LOGM(VARP, logh, LEV_INFO, T_PRE, "Error enstabilishing SSL context."); if (accept_timed_out){ SetError("SSL Handshake failed due to server timeout!"); }else{ SetErrorOpenSSL("SSL Handshake error:"); } goto err; } // Context enstabilished actual_cert = SSL_get_peer_certificate(ssl); peer_stack = SSL_get_peer_cert_chain(ssl); char buffer[1000]; // if (LogLevelMin(logh, LEV_DEBUG)) { LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate DN: %s", X509_NAME_oneline(X509_get_subject_name(actual_cert), buffer, 999)); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate CA: %s", X509_NAME_oneline(X509_get_issuer_name(actual_cert), buffer, 999)); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Stack Size: %d", sk_X509_num(peer_stack)); // } peer_cert = get_real_cert(actual_cert, peer_stack); if (peer_cert) { char *name = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, 0); own_subject = std::string(name); OPENSSL_free(name); } if (LogLevelMin(logh, LEV_DEBUG)){ for (int i = 0; i < sk_X509_num(peer_stack); i++) { X509 *cert = sk_X509_value(peer_stack, i); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate DN: %s", X509_NAME_oneline(X509_get_subject_name(cert), buffer, 999)); LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate CA: %s", X509_NAME_oneline(X509_get_issuer_name(cert), buffer, 999)); } } name = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, 0); if (name) peer_subject = std::string(name); OPENSSL_free(name); name = X509_NAME_oneline(X509_get_issuer_name(peer_cert), NULL, 0); if (name) peer_ca = std::string(name); OPENSSL_free(name); serial = get_peer_serial(actual_cert); peer_serial = std::string(serial ? serial : ""); OPENSSL_free(serial); return true; err: destroy_SSL_proxy_handler(ssl); SSL_free(ssl); SSL_CTX_free(ctx); return false; }
int main(int argc, char *argv[]) { // default paths currently point to my test certificates char *m_caCertPath; char *m_serverCert; char *m_serverKey; char *stoparg; m_caCertPath= argv[1]; fprintf(stdout, "phase1\n"); m_serverCert = strchr(m_caCertPath, ';'); fprintf(stdout, "phase2\n"); *m_serverCert++ ='\0'; m_serverKey = strchr(m_serverCert, ';'); fprintf(stdout, "phase3\n"); *m_serverKey++ ='\0'; stoparg = strchr(m_serverKey, ';'); fprintf(stdout, "phase4\n"); *stoparg++ = '\0'; fprintf(stdout, "ca:%s\ncert:%s\nkey:%s\nstop:%s\n", m_caCertPath, m_serverCert, m_serverKey, stoparg); SSL_CTX *m_sslCtx = NULL; // Initializing OpenSSL // FIXME should this only be called once? OpenSSL_add_all_algorithms(); SSLeay_add_all_algorithms(); SSL_load_error_strings(); ERR_load_crypto_strings(); ERR_load_BIO_strings(); SSL_library_init(); m_sslCtx = SSL_CTX_new( SSLv23_method() ); if (!m_sslCtx) { ERR_print_errors_fp( stdout ); printf("error1\n"); } SSL_CTX_set_options(m_sslCtx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); /* SSL_CTX_set_cipher_list(m_sslCtx, "ALL:!LOW:!EXP:!MD5:!MD2"); */ SSL_CTX_set_purpose(m_sslCtx, X509_PURPOSE_ANY); /* SSL_CTX_set_mode(m_sslCtx, SSL_MODE_AUTO_RETRY); */ printf("test\n"); // load server certificate if ( SSL_CTX_use_certificate_file( m_sslCtx, m_serverCert, SSL_FILETYPE_PEM ) <= 0 ) { ERR_print_errors_fp( stdout ); printf("error1\n"); } // load private key if ( SSL_CTX_use_PrivateKey_file( m_sslCtx, m_serverKey, SSL_FILETYPE_PEM) <= 0 ) { ERR_print_errors_fp( stdout ); printf("error2\n"); } // load trusted Certificate Authority if ( !SSL_CTX_load_verify_locations( m_sslCtx, 0, m_caCertPath ) ) { ERR_print_errors_fp( stdout ); printf("error3\n"); } // require peer (client) certificate verification SSL_CTX_set_verify( m_sslCtx, SSL_VERIFY_PEER, 0 ); // Set the verification depth to 1 SSL_CTX_set_verify_depth( m_sslCtx, 100 ); // set the verify call back to girdsite, which understands // proxy certificates SSL_CTX_set_cert_verify_callback( m_sslCtx, proxy_verify_callback_server, 0); // create new ssl structure and pass the fd to it SSL *m_sslCon = SSL_new( m_sslCtx ); BIO *bio = BIO_new_accept("33334"); if (BIO_do_accept(bio) <= 0) fprintf(stdout, "BIO_do_accept failed\n"); fprintf(stdout, "now accepting\n"); fprintf(stdout, "bio=%ld\n", bio); BIO_do_accept(bio); fprintf(stdout, "part1\n"); BIO *client= BIO_pop(bio); fprintf(stdout, "part2\n"); SSL_set_bio(m_sslCon, client, client); fprintf(stdout,"bio set\n"); // initiate the handshake int error; if ( (error = SSL_accept( m_sslCon )) <= 0 ) { unsigned long l; char buf[256]; #if SSLEAY_VERSION_NUMBER >= 0x00904100L const char *file; #else char *file; #endif char *dat; int line; /* WIN32 does not have the ERR_get_error_line_data */ /* exported, so simulate it till it is fixed */ /* in SSLeay-0.9.0 */ while ( ERR_peek_error() != 0 ) { int i; ERR_STATE *es; es = ERR_get_state(); i = (es->bottom+1)%ERR_NUM_ERRORS; if (es->err_data[i] == NULL) dat = (char*)""; else dat = es->err_data[i]; if (dat) { l = ERR_get_error_line(&file, &line); // if (debug) fprintf(stdout, "%s:%s,%d,%s\n", ERR_error_string(l, buf), file, line, dat); // error += std::string(ERR_reason_error_string(l)) + ":" + std::string(ERR_func_error_string(l)) + "\n"; } } /* fprintf(stdout, "%s\n", */ /* ERR_reason_error_string( ERR_get_error() )); */ fprintf(stdout, "ERROR\n"); exit(1); } fprintf(stdout, "Handshake done!\n"); /* connected */ sleep(100); exit(0); }