static int run_cert(X509 *crt, const char *nameincert, const struct set_name_fn *fn) { const char *const *pname = names; int failed = 0; for (; *pname != NULL; ++pname) { int samename = strcasecmp(nameincert, *pname) == 0; size_t namelen = strlen(*pname); char *name = OPENSSL_malloc(namelen); int match, ret; memcpy(name, *pname, namelen); match = -1; if (!TEST_int_ge(ret = X509_check_host(crt, name, namelen, 0, NULL), 0)) { failed = 1; } else if (fn->host) { if (ret == 1 && !samename) match = 1; if (ret == 0 && samename) match = 0; } else if (ret == 1) match = 1; if (!TEST_true(check_message(fn, "host", nameincert, match, *pname))) failed = 1; match = -1; if (!TEST_int_ge(ret = X509_check_host(crt, name, namelen, X509_CHECK_FLAG_NO_WILDCARDS, NULL), 0)) { failed = 1; } else if (fn->host) { if (ret == 1 && !samename) match = 1; if (ret == 0 && samename) match = 0; } else if (ret == 1) match = 1; if (!TEST_true(check_message(fn, "host-no-wildcards", nameincert, match, *pname))) failed = 1; match = -1; ret = X509_check_email(crt, name, namelen, 0); if (fn->email) { if (ret && !samename) match = 1; if (!ret && samename && strchr(nameincert, '@') != NULL) match = 0; } else if (ret) match = 1; if (!TEST_true(check_message(fn, "email", nameincert, match, *pname))) failed = 1; OPENSSL_free(name); } return failed == 0; }
static void run_cert(X509 *crt, const char *nameincert, const struct set_name_fn *fn) { const char *const *pname = names; while (*pname) { int samename = sgx_strcasecmp(nameincert, *pname) == 0; size_t namelen = sgx_strlen(*pname); char *name = sgx_malloc(namelen); int match, ret; sgx_memcpy(name, *pname, namelen); ret = X509_check_host(crt, name, namelen, 0, NULL); match = -1; if (ret < 0) { fprintf(stderr, "internal error in X509_check_host"); ++errors; } else if (fn->host) { if (ret == 1 && !samename) match = 1; if (ret == 0 && samename) match = 0; } else if (ret == 1) match = 1; check_message(fn, "host", nameincert, match, *pname); ret = X509_check_host(crt, name, namelen, X509_CHECK_FLAG_NO_WILDCARDS, NULL); match = -1; if (ret < 0) { fprintf(stderr, "internal error in X509_check_host"); ++errors; } else if (fn->host) { if (ret == 1 && !samename) match = 1; if (ret == 0 && samename) match = 0; } else if (ret == 1) match = 1; check_message(fn, "host-no-wildcards", nameincert, match, *pname); ret = X509_check_email(crt, name, namelen, 0); match = -1; if (fn->email) { if (ret && !samename) match = 1; if (!ret && samename && sgx_strchr(nameincert, '@') != NULL) match = 0; } else if (ret) match = 1; check_message(fn, "email", nameincert, match, *pname); ++pname; sgx_free(name); } }
static inline int tls_check_cert(shout_tls_t *tls) { X509 *cert = SSL_get_peer_certificate(tls->ssl); int cert_ok = 0; if (!cert) return SHOUTERR_TLSBADCERT; do { if (SSL_get_verify_result(tls->ssl) != X509_V_OK) break; #ifdef XXX_HAVE_X509_check_host if (X509_check_host(cert, tls->host, 0, 0, NULL) != 1) break; #else if (tls_check_host(cert, tls->host) != SHOUTERR_SUCCESS) break; #endif /* ok, all test passed... */ cert_ok = 1; } while (0); X509_free(cert); return cert_ok ? SHOUTERR_SUCCESS : SHOUTERR_TLSBADCERT; }
int main(int argc, char **argv) { if (argc != 3) { usage(argv[0]); } BIO *bio_err=BIO_new_fp(stderr, BIO_NOCLOSE); if (bio_err == NULL) { perror("BIO_ne_fp(stderr)"); exit(1); } //+ Features TLS-Client-OpenSSL-Init // The following call prints an error message and calls exit() if // the OpenSSL configuration file is unreadable. OPENSSL_config(NULL); // Provide human-readable error messages. SSL_load_error_strings(); // Register ciphers. SSL_library_init(); //- //+ Features TLS-Client-OpenSSL-CTX // Configure a client connection context. Send a hendshake for the // highest supported TLS version, and disable compression. const SSL_METHOD *const req_method = SSLv23_client_method(); SSL_CTX *const ctx = SSL_CTX_new(req_method); if (ctx == NULL) { ERR_print_errors(bio_err); exit(1); } SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION); // Adjust the ciphers list based on a whitelist. First enable all // ciphers of at least medium strength, to get the list which is // compiled into OpenSSL. if (SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM") != 1) { ERR_print_errors(bio_err); exit(1); } { // Create a dummy SSL session to obtain the cipher list. SSL *ssl = SSL_new(ctx); if (ssl == NULL) { ERR_print_errors(bio_err); exit(1); } STACK_OF(SSL_CIPHER) *active_ciphers = SSL_get_ciphers(ssl); if (active_ciphers == NULL) { ERR_print_errors(bio_err); exit(1); } // Whitelist of candidate ciphers. static const char *const candidates[] = { "AES128-GCM-SHA256", "AES128-SHA256", "AES256-SHA256", // strong ciphers "AES128-SHA", "AES256-SHA", // strong ciphers, also in older versions "RC4-SHA", "RC4-MD5", // backwards compatibility, supposed to be weak "DES-CBC3-SHA", "DES-CBC3-MD5", // more backwards compatibility NULL }; // Actually selected ciphers. char ciphers[300]; ciphers[0] = '\0'; for (const char *const *c = candidates; *c; ++c) { for (int i = 0; i < sk_SSL_CIPHER_num(active_ciphers); ++i) { if (strcmp(SSL_CIPHER_get_name(sk_SSL_CIPHER_value(active_ciphers, i)), *c) == 0) { if (*ciphers) { strcat(ciphers, ":"); } strcat(ciphers, *c); break; } } } SSL_free(ssl); // Apply final cipher list. if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) { ERR_print_errors(bio_err); exit(1); } } // Load the set of trusted root certificates. if (!SSL_CTX_set_default_verify_paths(ctx)) { ERR_print_errors(bio_err); exit(1); } //- const char *host = argv[1]; const char *service = argv[2]; // Perform name lookup, create the TCP client socket, and connect to // the server. int sockfd = tcp_connect(host, service); if (sockfd < 0) { perror("connect"); exit(1); } // Deactivate the Nagle algorithm. //+ Features TLS-Nagle const int val = 1; int ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); if (ret < 0) { perror("setsockopt(TCP_NODELAY)"); exit(1); } //- //+ Features TLS-Client-OpenSSL-Connect // Create the connection object. SSL *ssl = SSL_new(ctx); if (ssl == NULL) { ERR_print_errors(bio_err); exit(1); } SSL_set_fd(ssl, sockfd); // Enable the ServerNameIndication extension if (!SSL_set_tlsext_host_name(ssl, host)) { ERR_print_errors(bio_err); exit(1); } // Perform the TLS handshake with the server. ret = SSL_connect(ssl); if (ret != 1) { // Error status can be 0 or negative. ssl_print_error_and_exit(ssl, "SSL_connect", ret); } // Obtain the server certificate. X509 *peercert = SSL_get_peer_certificate(ssl); if (peercert == NULL) { fprintf(stderr, "peer certificate missing"); exit(1); } // Check the certificate verification result. Allow an explicit // certificate validation override in case verification fails. int verifystatus = SSL_get_verify_result(ssl); if (verifystatus != X509_V_OK && !certificate_validity_override(peercert)) { fprintf(stderr, "SSL_connect: verify result: %s\n", X509_verify_cert_error_string(verifystatus)); exit(1); } // Check if the server certificate matches the host name used to // establish the connection. // FIXME: Currently needs OpenSSL 1.1. if (X509_check_host(peercert, (const unsigned char *)host, strlen(host), 0) != 1 && !certificate_host_name_override(peercert, host)) { fprintf(stderr, "SSL certificate does not match host name\n"); exit(1); } X509_free(peercert); //- //+ Features TLS-Client-OpenSSL-Connection-Use const char *const req = "GET / HTTP/1.0\r\n\r\n"; if (SSL_write(ssl, req, strlen(req)) < 0) { ssl_print_error_and_exit(ssl, "SSL_write", ret); } char buf[4096]; ret = SSL_read(ssl, buf, sizeof(buf)); if (ret < 0) { ssl_print_error_and_exit(ssl, "SSL_read", ret); } //- write(STDOUT_FILENO, buf, ret); //+ Features TLS-OpenSSL-Connection-Close // Send the close_notify alert. ret = SSL_shutdown(ssl); switch (ret) { case 1: // A close_notify alert has already been received. break; case 0: // Wait for the close_notify alert from the peer. ret = SSL_shutdown(ssl); switch (ret) { case 0: fprintf(stderr, "info: second SSL_shutdown returned zero\n"); break; case 1: break; default: ssl_print_error_and_exit(ssl, "SSL_shutdown 2", ret); } break; default: ssl_print_error_and_exit(ssl, "SSL_shutdown 1", ret); } SSL_free(ssl); close(sockfd); //- //+ Features TLS-OpenSSL-Context-Close SSL_CTX_free(ctx); //- BIO_free(bio_err); return 0; }
bool OpenSSLBase::handshake() { doTLSOperation( TLSHandshake ); if( !m_secure ) return true; long res = SSL_get_verify_result( m_ssl ); if( res != X509_V_OK ) m_certInfo.status = CertInvalid; else m_certInfo.status = CertOk; X509* peer = SSL_get_peer_certificate( m_ssl ); if( peer ) { char peer_CN[256]; X509_NAME_get_text_by_NID( X509_get_issuer_name( peer ), NID_commonName, peer_CN, sizeof( peer_CN ) ); m_certInfo.issuer = peer_CN; X509_NAME_get_text_by_NID( X509_get_subject_name( peer ), NID_commonName, peer_CN, sizeof( peer_CN ) ); m_certInfo.server = peer_CN; m_certInfo.date_from = ASN1Time2UnixTime( X509_get_notBefore( peer ) ); m_certInfo.date_to = ASN1Time2UnixTime( X509_get_notAfter( peer ) ); std::string p( peer_CN ); std::transform( p.begin(), p.end(), p.begin(), tolower ); #if defined OPENSSL_VERSION_NUMBER && ( OPENSSL_VERSION_NUMBER >= 0x10002000 ) res = X509_check_host( peer, p.c_str(), p.length(), X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS, 0 ); if( res <= 0 ) // 0: verification failed; -1: internal error; -2 input is malformed m_certInfo.status |= CertWrongPeer; #else if( p != m_server ) m_certInfo.status |= CertWrongPeer; #endif // OPENSSL_VERSION_NUMBER >= 0x10002000 if( ASN1_UTCTIME_cmp_time_t( X509_get_notBefore( peer ), time( 0 ) ) != -1 ) m_certInfo.status |= CertNotActive; if( ASN1_UTCTIME_cmp_time_t( X509_get_notAfter( peer ), time( 0 ) ) != 1 ) m_certInfo.status |= CertExpired; X509_free( peer ); } else { m_certInfo.status = CertInvalid; } const char* tmp; tmp = SSL_get_cipher_name( m_ssl ); if( tmp ) m_certInfo.cipher = tmp; SSL_SESSION* sess = SSL_get_session( m_ssl ); if( sess ) { switch( SSL_SESSION_get_protocol_version( sess ) ) { case TLS1_VERSION: m_certInfo.protocol = "TLSv1"; break; case TLS1_1_VERSION: m_certInfo.protocol = "TLSv1.1"; break; case TLS1_2_VERSION: m_certInfo.protocol = "TLSv1.2"; break; #ifdef TLS1_3_VERSION case TLS1_3_VERSION: m_certInfo.protocol = "TLSv1.3"; break; #endif // TLS1_3_VERSION default: m_certInfo.protocol = "Unknown TLS version"; break; } } tmp = SSL_COMP_get_name( SSL_get_current_compression( m_ssl ) ); if( tmp ) m_certInfo.compression = tmp; m_valid = true; m_handler->handleHandshakeResult( this, true, m_certInfo ); return true; }