void *thread_main (void *arg) { int err, buflen, read; int sd; SSL_CTX *ctx = (SSL_CTX *) arg; struct sockaddr_in dest_sin; int sock; #ifdef _WIN32 PHOSTENT phe; WORD wVersionRequested; WSADATA wsaData; #endif /* */ SSL *ssl; X509 *server_cert; char *str; char buf[1024]; SSL_METHOD *meth; FILE *fp; #ifdef _WIN32 wVersionRequested = MAKEWORD (2, 2); err = WSAStartup (wVersionRequested, &wsaData); if (err != 0) { printf ("WSAStartup err\n"); return -1; } #endif /* */ //首先建立连接 sock = socket (AF_INET, SOCK_STREAM, 0); dest_sin.sin_family = AF_INET; dest_sin.sin_addr.s_addr = inet_addr ("127.0.0.1"); dest_sin.sin_port = htons (8888); again:err = connect (sock, (struct sockaddr_in *) &dest_sin, sizeof (dest_sin)); if (err < 0) { sleep (1); goto again; } //安全连接要求在连接建立后进行握手 ssl = SSL_new (ctx); if (ssl == NULL) { printf ("ss new err\n"); return; } SSL_set_fd (ssl, sock); //请求SSL连接 err = SSL_connect (ssl); if (err < 0) { printf ("SSL_connect err\n"); return; } printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); // server_cert = SSL_get_peer_certificate (ssl); printf ("Server certificate:\n"); //获得服务端证书subject并转变成字符型,以便进行打印 str = X509_NAME_oneline (X509_get_subject_name (server_cert), 0, 0); printf ("\t subject: %s\n", str); OPENSSL_free (str); //获得客户端证书issuer并转变成字符型,以便进行打印 str = X509_NAME_oneline (X509_get_issuer_name (server_cert), 0, 0); printf ("\t issuer: %s\n", str); OPENSSL_free (str); X509_free (server_cert); //进行安全会话 err = SSL_write (ssl, "Hello World!", strlen ("Hello World!")); if (err < 0) { printf ("ssl write err\n"); return; } #if 0 memset (buf, 0, ONE_BUF_SIZE); err = SSL_read (ssl, buf, sizeof (buf) - 1); if (err < 0) { printf ("ssl read err\n"); return; } buf[err] = '\0'; printf ("Got %d chars:'%s'\n", err, buf); #endif /* */ SSL_shutdown (ssl); SSL_free (ssl); close (sock); /* send SSL/TLS close_notify */ }
/* FIXME: Master-Key, Extensions, CA bits (openssl x509 -text -in servcert.pem) */ int _SSL_get_cert_info (struct cert_info *cert_info, SSL * ssl) { X509 *peer_cert; EVP_PKEY *peer_pkey; /* EVP_PKEY *ca_pkey; */ /* EVP_PKEY *tmp_pkey; */ char notBefore[64]; char notAfter[64]; int alg; int sign_alg; if (!(peer_cert = SSL_get_peer_certificate (ssl))) return (1); /* FATAL? */ X509_NAME_oneline (X509_get_subject_name (peer_cert), cert_info->subject, sizeof (cert_info->subject)); X509_NAME_oneline (X509_get_issuer_name (peer_cert), cert_info->issuer, sizeof (cert_info->issuer)); broke_oneline (cert_info->subject, cert_info->subject_word); broke_oneline (cert_info->issuer, cert_info->issuer_word); alg = OBJ_obj2nid (peer_cert->cert_info->key->algor->algorithm); sign_alg = OBJ_obj2nid (peer_cert->sig_alg->algorithm); ASN1_TIME_snprintf (notBefore, sizeof (notBefore), X509_get_notBefore (peer_cert)); ASN1_TIME_snprintf (notAfter, sizeof (notAfter), X509_get_notAfter (peer_cert)); peer_pkey = X509_get_pubkey (peer_cert); strncpy (cert_info->algorithm, (alg == NID_undef) ? "Unknown" : OBJ_nid2ln (alg), sizeof (cert_info->algorithm)); cert_info->algorithm_bits = EVP_PKEY_bits (peer_pkey); strncpy (cert_info->sign_algorithm, (sign_alg == NID_undef) ? "Unknown" : OBJ_nid2ln (sign_alg), sizeof (cert_info->sign_algorithm)); /* EVP_PKEY_bits(ca_pkey)); */ cert_info->sign_algorithm_bits = 0; strncpy (cert_info->notbefore, notBefore, sizeof (cert_info->notbefore)); strncpy (cert_info->notafter, notAfter, sizeof (cert_info->notafter)); EVP_PKEY_free (peer_pkey); /* SSL_SESSION_print_fp(stdout, SSL_get_session(ssl)); */ /* if (ssl->session->sess_cert->peer_rsa_tmp) { tmp_pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(tmp_pkey, ssl->session->sess_cert->peer_rsa_tmp); cert_info->rsa_tmp_bits = EVP_PKEY_bits (tmp_pkey); EVP_PKEY_free(tmp_pkey); } else fprintf(stderr, "REMOTE SIDE DOESN'T PROVIDES ->peer_rsa_tmp\n"); */ cert_info->rsa_tmp_bits = 0; X509_free (peer_cert); return (0); }
/* This function is called on a socket file descriptor once the connection has been * established and we're ready to negotiate SSL. If the SSL handshake fails for some * reason (such as the host on the other end not using SSL), it will return 0 for * failure. Success returns 1. */ static int FinishConnection(TCLinkCon *c, int sd) { int ssl_connected, is_error, errcode, res; X509 *server_cert; time_t start, remaining; fd_set in, out, err; struct timeval tv; /* check if socket has connected successfully */ int val; int /*socklen_t*/ size = 4; getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*)&val, &size); if (val != 0) return 0; SSL_clear(c->ssl); SSL_set_fd(c->ssl, sd); ssl_connected = 0; is_error = 0; start = time(0); while (!ssl_connected && !is_error) { remaining = 5 - (time(0) - start); if (remaining <= 0) { is_error = 1; break; } res = SSL_connect(c->ssl); ssl_connected = ((res == 1) && SSL_is_init_finished(c->ssl)); if (!ssl_connected) { FD_ZERO(&in); FD_SET((unsigned)sd, &in); FD_ZERO(&out); FD_SET((unsigned)sd, &out); FD_ZERO(&err); FD_SET((unsigned)sd, &err); /* the documentation does not suggest that both error types occur at the same time so * the retry logic will consume all the outstanding events * we do not actually use oob data, but if it is sent, it is treated as an error all the * same */ errcode = SSL_get_error(c->ssl, res); switch (errcode) { case SSL_ERROR_NONE: /* no error, we should have a connection, check again */ break; case SSL_ERROR_WANT_READ: /* no error, just wait for more data */ tv.tv_sec = remaining; tv.tv_usec = 0; /* posix-2001 says the function will modify the appropriate descriptors */ if (select(sd+1, &in, NULL, &err, &tv) < 0 || FD_ISSET((unsigned)sd, &err) ) is_error = 1; break; case SSL_ERROR_WANT_WRITE: /* no error, just wait for more data */ tv.tv_sec = remaining; tv.tv_usec = 0; if (select(sd+1, NULL, &out, &err, &tv) < 0 || FD_ISSET((unsigned)sd, &err) ) is_error = 1; break; case SSL_ERROR_ZERO_RETURN: /* peer closed the connection */ case SSL_ERROR_SSL: /* error in SSL handshake */ default: is_error = 1; } } } if (is_error) { return 0; } #ifdef WIN32 u_long param = 0; ioctlsocket(sd, FIONBIO, ¶m); // make the socket blocking again #else fcntl(sd, F_SETFL, 0); /* make the socket blocking again */ #endif /* verify that server certificate is authentic */ server_cert = SSL_get_peer_certificate(c->ssl); if (!server_cert) { X509_free(server_cert); return 0; } if (c->validate_cert && c->validate_cert(0, server_cert) != 0) { X509_free(server_cert); return 0; } X509_free(server_cert); return 1; }
static int tls_drv_control(ErlDrvData handle, unsigned int command, char *buf, int len, char **rbuf, int rlen) { tls_data *d = (tls_data *)handle; int res; int size; ErlDrvBinary *b; X509 *cert; unsigned int flags = command; command &= 0xffff; ERR_clear_error(); switch (command) { case SET_CERTIFICATE_FILE_ACCEPT: case SET_CERTIFICATE_FILE_CONNECT: { time_t mtime = 0; SSL_CTX *ssl_ctx = hash_table_lookup(buf, &mtime); if (is_key_file_modified(buf, &mtime) || ssl_ctx == NULL) { SSL_CTX *ctx; hash_table_insert(buf, mtime, NULL); ctx = SSL_CTX_new(SSLv23_method()); die_unless(ctx, "SSL_CTX_new failed"); res = SSL_CTX_use_certificate_chain_file(ctx, buf); die_unless(res > 0, "SSL_CTX_use_certificate_file failed"); res = SSL_CTX_use_PrivateKey_file(ctx, buf, SSL_FILETYPE_PEM); die_unless(res > 0, "SSL_CTX_use_PrivateKey_file failed"); res = SSL_CTX_check_private_key(ctx); die_unless(res > 0, "SSL_CTX_check_private_key failed"); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_default_verify_paths(ctx); #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); #endif /* SSL_CTX_load_verify_locations(ctx, "/etc/ejabberd/ca_certificates.pem", NULL); */ /* SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ejabberd/ca_certs/"); */ /* This IF is commented to allow verification in all cases: */ /* if (command == SET_CERTIFICATE_FILE_ACCEPT) */ /* { */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verify_callback); /* } */ ssl_ctx = ctx; hash_table_insert(buf, mtime, ssl_ctx); } d->ssl = SSL_new(ssl_ctx); die_unless(d->ssl, "SSL_new failed"); if (flags & VERIFY_NONE) SSL_set_verify(d->ssl, SSL_VERIFY_NONE, verify_callback); d->bio_read = BIO_new(BIO_s_mem()); d->bio_write = BIO_new(BIO_s_mem()); SSL_set_bio(d->ssl, d->bio_read, d->bio_write); if (command == SET_CERTIFICATE_FILE_ACCEPT) { SSL_set_options(d->ssl, SSL_OP_NO_TICKET); SSL_set_accept_state(d->ssl); } else { SSL_set_options(d->ssl, SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET); SSL_set_connect_state(d->ssl); } break; } case SET_ENCRYPTED_INPUT: die_unless(d->ssl, "SSL not initialized"); BIO_write(d->bio_read, buf, len); break; case SET_DECRYPTED_OUTPUT: die_unless(d->ssl, "SSL not initialized"); res = SSL_write(d->ssl, buf, len); if (res <= 0) { res = SSL_get_error(d->ssl, res); if (res == SSL_ERROR_WANT_READ || res == SSL_ERROR_WANT_WRITE) { b = driver_alloc_binary(1); b->orig_bytes[0] = 2; *rbuf = (char *)b; return 1; } else { die_unless(0, "SSL_write failed"); } } break; case GET_ENCRYPTED_OUTPUT: die_unless(d->ssl, "SSL not initialized"); size = BIO_ctrl_pending(d->bio_write) + 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; BIO_read(d->bio_write, b->orig_bytes + 1, size - 1); *rbuf = (char *)b; return size; case GET_DECRYPTED_INPUT: if (!SSL_is_init_finished(d->ssl)) { res = SSL_do_handshake(d->ssl); if (res <= 0) die_unless(SSL_get_error(d->ssl, res) == SSL_ERROR_WANT_READ, "SSL_do_handshake failed"); } else { size = BUF_SIZE + 1; rlen = 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; while ((res = SSL_read(d->ssl, b->orig_bytes + rlen, BUF_SIZE)) > 0) { //printf("%d bytes of decrypted data read from state machine\r\n",res); rlen += res; size += BUF_SIZE; b = driver_realloc_binary(b, size); } if (res < 0) { int err = SSL_get_error(d->ssl, res); if (err == SSL_ERROR_WANT_READ) { //printf("SSL_read wants more data\r\n"); //return 0; } // TODO } b = driver_realloc_binary(b, rlen); *rbuf = (char *)b; return rlen; } break; case GET_PEER_CERTIFICATE: cert = SSL_get_peer_certificate(d->ssl); if (cert == NULL) { b = driver_alloc_binary(1); b->orig_bytes[0] = 1; *rbuf = (char *)b; return 1; } else { unsigned char *tmp_buf; rlen = i2d_X509(cert, NULL); if (rlen >= 0) { rlen++; b = driver_alloc_binary(rlen); b->orig_bytes[0] = 0; tmp_buf = (unsigned char *)&b->orig_bytes[1]; i2d_X509(cert, &tmp_buf); X509_free(cert); *rbuf = (char *)b; return rlen; } else X509_free(cert); } break; case GET_VERIFY_RESULT: b = driver_alloc_binary(1); b->orig_bytes[0] = SSL_get_verify_result(d->ssl); *rbuf = (char *)b; return 1; break; } b = driver_alloc_binary(1); b->orig_bytes[0] = 0; *rbuf = (char *)b; return 1; }
int ssl_handshake(struct Client *cptr) { char *str; int err; cptr->ssl = (struct SSL*) SSL_new (ctx); // cptr->use_ssl=1; CHK_NULL (cptr->ssl); SSL_set_fd ((SSL *)cptr->ssl, cptr->fd); set_non_blocking(cptr->fd); err = ircd_SSL_accept (cptr, cptr->fd); if ((err)==-1) { irclog(L_ERROR,"Lost connection to %s:Error in SSL_accept()", get_client_name(cptr, TRUE)); SSL_shutdown((SSL *)cptr->ssl); SSL_free((SSL *)cptr->ssl); cptr->ssl = NULL; return 0; } /* Get the cipher - opt */ SetSecure(cptr); irclog (L_DEBUG, "SSL connection using %s", SSL_get_cipher ((SSL *)cptr->ssl)); /* Get client's certificate (note: beware of dynamic * allocation) - opt */ cptr->client_cert = (struct X509*)SSL_get_peer_certificate ((SSL *)cptr->ssl); if (cptr->client_cert != NULL) { irclog (L_DEBUG,"Client certificate:"); str = X509_NAME_oneline (X509_get_subject_name ((X509*)cptr->client_cert), 0, 0); CHK_NULL (str); irclog (L_DEBUG, "\t subject: %s", str); // Bejvavalo // Free (str); free(str); str = X509_NAME_oneline (X509_get_issuer_name ((X509*)cptr->client_cert), 0, 0); CHK_NULL (str); irclog (L_DEBUG, "\t issuer: %s", str); // Bejvavalo // Free (str); free(str); /* We could do all sorts of certificate * verification stuff here before * deallocating the certificate. */ X509_free ((X509*)cptr->client_cert); } else irclog (L_DEBUG, "Client does not have certificate."); return 1; }
tcp_stream_t * tcp_stream_create_ssl_from_fd(int fd, const char *hostname, const tcp_ssl_info_t *tsi, char *errbuf, size_t errlen) { char errmsg[120]; tcp_stream_t *ts = calloc(1, sizeof(tcp_stream_t)); ts->ts_fd = fd; if((ts->ts_ssl = SSL_new(ssl_ctx)) == NULL) goto bad_ssl; if(SSL_set_fd(ts->ts_ssl, fd) == 0) goto bad_ssl; if(tsi->key != NULL) { BIO *cbio = BIO_new_mem_buf((char *)tsi->key, -1); EVP_PKEY *key = PEM_read_bio_PrivateKey(cbio, NULL, NULL, NULL); BIO_free(cbio); if(key == NULL) { snprintf(errbuf, errlen, "Unable to load private key"); goto bad; } SSL_use_PrivateKey(ts->ts_ssl, key); EVP_PKEY_free(key); } if(tsi->cert != NULL) { BIO *cbio = BIO_new_mem_buf((char *)tsi->cert, -1); X509 *cert = PEM_read_bio_X509(cbio, NULL, 0, NULL); BIO_free(cbio); if(cert == NULL) { snprintf(errbuf, errlen, "Unable to load certificate"); goto bad; } SSL_use_certificate(ts->ts_ssl, cert); X509_free(cert); } if(SSL_connect(ts->ts_ssl) <= 0) { goto bad_ssl; } SSL_set_mode(ts->ts_ssl, SSL_MODE_AUTO_RETRY); X509 *peer = SSL_get_peer_certificate(ts->ts_ssl); if(peer == NULL) { goto bad_ssl; } int err = SSL_get_verify_result(ts->ts_ssl); if(err != X509_V_OK) { snprintf(errbuf, errlen, "Certificate error: %s", X509_verify_cert_error_string(err)); X509_free(peer); goto bad; } if(verify_hostname(hostname, peer, errbuf, errlen)) { X509_free(peer); goto bad; } X509_free(peer); ts->ts_fd = fd; htsbuf_queue_init(&ts->ts_spill, INT32_MAX); htsbuf_queue_init(&ts->ts_sendq, INT32_MAX); ts->ts_write = ssl_write; ts->ts_read = ssl_read; return ts; bad_ssl: ERR_error_string(ERR_get_error(), errmsg); snprintf(errbuf, errlen, "SSL: %s", errmsg); bad: tcp_close(ts); return NULL; }
ResponseCode OpenSSLConnection::ConnectInternal() { ResponseCode networkResponse = ResponseCode::SUCCESS; X509_VERIFY_PARAM *param = nullptr; server_tcp_socket_fd_ = socket(AF_INET, SOCK_STREAM, 0); if (-1 == server_tcp_socket_fd_) { return ResponseCode::NETWORK_TCP_SETUP_ERROR; } AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Root CA : %s", root_ca_location_.c_str()); if (!SSL_CTX_load_verify_locations(p_ssl_context_, root_ca_location_.c_str(), NULL)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Root CA Loading error"); return ResponseCode::NETWORK_SSL_ROOT_CRT_PARSE_ERROR; } if (0 < device_cert_location_.length() && 0 < device_private_key_location_.length()) { AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device crt : %s", device_cert_location_.c_str()); if (!SSL_CTX_use_certificate_file(p_ssl_context_, device_cert_location_.c_str(), SSL_FILETYPE_PEM)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Certificate Loading error"); return ResponseCode::NETWORK_SSL_DEVICE_CRT_PARSE_ERROR; } AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device privkey : %s", device_private_key_location_.c_str()); if (1 != SSL_CTX_use_PrivateKey_file(p_ssl_context_, device_private_key_location_.c_str(), SSL_FILETYPE_PEM)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Private Key Loading error"); return ResponseCode::NETWORK_SSL_KEY_PARSE_ERROR; } } p_ssl_handle_ = SSL_new(p_ssl_context_); // Requires OpenSSL v1.0.2 and above if (server_verification_flag_) { param = SSL_get0_param(p_ssl_handle_); // Enable automatic hostname checks X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); // Check if it is an IPv4 or an IPv6 address to enable ip checking // Enable host name check otherwise char dst[INET6_ADDRSTRLEN]; if (inet_pton(AF_INET, endpoint_.c_str(), (void *) dst) || inet_pton(AF_INET6, endpoint_.c_str(), (void *) dst)) { X509_VERIFY_PARAM_set1_ip_asc(param, endpoint_.c_str()); } else { X509_VERIFY_PARAM_set1_host(param, endpoint_.c_str(), 0); } } // Configure a non-zero callback if desired SSL_set_verify(p_ssl_handle_, SSL_VERIFY_PEER, nullptr); networkResponse = ConnectTCPSocket(); if (ResponseCode::SUCCESS != networkResponse) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, "TCP Connection error"); return networkResponse; } SSL_set_fd(p_ssl_handle_, server_tcp_socket_fd_); networkResponse = SetSocketToNonBlocking(); if (ResponseCode::SUCCESS != networkResponse) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Unable to set the socket to Non-Blocking"); return networkResponse; } networkResponse = AttemptConnect(); if (X509_V_OK != SSL_get_verify_result(p_ssl_handle_)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Server Certificate Verification failed."); networkResponse = ResponseCode::NETWORK_SSL_CONNECT_ERROR; } else { // ensure you have a valid certificate returned, otherwise no certificate exchange happened if (nullptr == SSL_get_peer_certificate(p_ssl_handle_)) { AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " No certificate exchange happened"); networkResponse = ResponseCode::NETWORK_SSL_CONNECT_ERROR; } } if (ResponseCode::SUCCESS == networkResponse) { is_connected_ = true; } return networkResponse; }
/** Search for a hostname match in the SubjectAlternativeNames. */ uint32_t check_san (SSL *ssl, const char *hostname) { X509 *cert; int extcount, ok = 0; /* What an OpenSSL mess ... */ if (NULL == (cert = SSL_get_peer_certificate(ssl))) { die ("Getting certificate failed\n"); } if ((extcount = X509_get_ext_count(cert)) > 0) { int i; for (i = 0; i < extcount; ++i) { const char *extstr; X509_EXTENSION *ext; ext = X509_get_ext(cert, i); extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (!strcmp(extstr, "subjectAltName")) { int j; void *extvalstr; const unsigned char *tmp; STACK_OF(CONF_VALUE) *val; CONF_VALUE *nval; #if OPENSSL_VERSION_NUMBER >= 0x10000000L const #endif X509V3_EXT_METHOD *method; if (!(method = X509V3_EXT_get(ext))) { break; } tmp = ext->value->data; if (method->it) { extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length, ASN1_ITEM_ptr(method->it)); } else { extvalstr = method->d2i(NULL, &tmp, ext->value->length); } if (!extvalstr) { break; } if (method->i2v) { val = method->i2v(method, extvalstr, NULL); for (j = 0; j < sk_CONF_VALUE_num(val); ++j) { nval = sk_CONF_VALUE_value(val, j); if ((!strcasecmp(nval->name, "DNS") && !strcasecmp(nval->value, hostname) ) || (!strcasecmp(nval->name, "iPAddress") && !strcasecmp(nval->value, hostname))) { verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print ok = 1; break; } // Attempt to match subjectAltName DNS names if (!strcasecmp(nval->name, "DNS")) { ok = check_wildcard_match_rfc2595(hostname, nval->value); if (ok) { break; } } verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string! } } } else { verb ("V: found non subjectAltName extension\n"); } if (ok) { break; } } } else { verb ("V: no X509_EXTENSION field(s) found\n"); } X509_free(cert); return ok; }
Str ssl_get_certificate(SSL * ssl, char *hostname) { BIO *bp; X509 *x; X509_NAME *xn; char *p; int len; Str s; char buf[2048]; Str amsg = NULL; Str emsg; char *ans; if (ssl == NULL) return NULL; x = SSL_get_peer_certificate(ssl); if (x == NULL) { if (accept_this_site && strcasecmp(accept_this_site->ptr, hostname) == 0) ans = "y"; else { /* FIXME: gettextize? */ emsg = Strnew_charp("No SSL peer certificate: accept? (y/n)"); ans = inputAnswer(emsg->ptr); } if (ans && TOLOWER(*ans) == 'y') /* FIXME: gettextize? */ amsg = Strnew_charp ("Accept SSL session without any peer certificate"); else { /* FIXME: gettextize? */ char *e = "This SSL session was rejected " "to prevent security violation: no peer certificate"; disp_err_message(e, FALSE); free_ssl_ctx(); return NULL; } if (amsg) disp_err_message(amsg->ptr, FALSE); ssl_accept_this_site(hostname); /* FIXME: gettextize? */ s = amsg ? amsg : Strnew_charp("valid certificate"); return s; } /* check the cert chain. * The chain length is automatically checked by OpenSSL when we * set the verify depth in the ctx. */ if (ssl_verify_server) { long verr; if ((verr = SSL_get_verify_result(ssl)) != X509_V_OK) { const char *em = X509_verify_cert_error_string(verr); if (accept_this_site && strcasecmp(accept_this_site->ptr, hostname) == 0) ans = "y"; else { /* FIXME: gettextize? */ emsg = Sprintf("%s: accept? (y/n)", em); ans = inputAnswer(emsg->ptr); } if (ans && TOLOWER(*ans) == 'y') { /* FIXME: gettextize? */ amsg = Sprintf("Accept unsecure SSL session: " "unverified: %s", em); } else { /* FIXME: gettextize? */ char *e = Sprintf("This SSL session was rejected: %s", em)->ptr; disp_err_message(e, FALSE); free_ssl_ctx(); return NULL; } } } emsg = ssl_check_cert_ident(x, hostname); if (emsg != NULL) { if (accept_this_site && strcasecmp(accept_this_site->ptr, hostname) == 0) ans = "y"; else { Str ep = Strdup(emsg); if (ep->length > COLS - 16) Strshrink(ep, ep->length - (COLS - 16)); Strcat_charp(ep, ": accept? (y/n)"); ans = inputAnswer(ep->ptr); } if (ans && TOLOWER(*ans) == 'y') { /* FIXME: gettextize? */ amsg = Strnew_charp("Accept unsecure SSL session:"); Strcat(amsg, emsg); } else { /* FIXME: gettextize? */ char *e = "This SSL session was rejected " "to prevent security violation"; disp_err_message(e, FALSE); free_ssl_ctx(); return NULL; } } if (amsg) disp_err_message(amsg->ptr, FALSE); ssl_accept_this_site(hostname); /* FIXME: gettextize? */ s = amsg ? amsg : Strnew_charp("valid certificate"); Strcat_charp(s, "\n"); xn = X509_get_subject_name(x); if (X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)) == -1) Strcat_charp(s, " subject=<unknown>"); else Strcat_m_charp(s, " subject=", buf, NULL); xn = X509_get_issuer_name(x); if (X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)) == -1) Strcat_charp(s, ": issuer=<unknown>"); else Strcat_m_charp(s, ": issuer=", buf, NULL); Strcat_charp(s, "\n\n"); bp = BIO_new(BIO_s_mem()); X509_print(bp, x); len = (int)BIO_ctrl(bp, BIO_CTRL_INFO, 0, (char *)&p); Strcat_charp_n(s, p, len); BIO_free_all(bp); X509_free(x); return s; }
int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){ # ifdef USE_OPENSSL X509 *certificate=NULL; X509_NAME *subj=NULL; char timestamp[50] = ""; char cn[MAX_CN_LENGTH]= ""; int cnlen =-1; int status=STATE_UNKNOWN; ASN1_STRING *tm; int offset; struct tm stamp; float time_left; int days_left; int time_remaining; time_t tm_t; certificate=SSL_get_peer_certificate(s); if (!certificate) { printf("%s\n",_("CRITICAL - Cannot retrieve server certificate.")); return STATE_CRITICAL; } /* Extract CN from certificate subject */ subj=X509_get_subject_name(certificate); if (!subj) { printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject.")); return STATE_CRITICAL; } cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn)); if (cnlen == -1) strcpy(cn, _("Unknown CN")); /* Retrieve timestamp of certificate */ tm = X509_get_notAfter(certificate); /* Generate tm structure to process timestamp */ if (tm->type == V_ASN1_UTCTIME) { if (tm->length < 10) { printf("%s\n", _("CRITICAL - Wrong time format in certificate.")); return STATE_CRITICAL; } else { stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0'); if (stamp.tm_year < 50) stamp.tm_year += 100; offset = 0; } } else { if (tm->length < 12) { printf("%s\n", _("CRITICAL - Wrong time format in certificate.")); return STATE_CRITICAL; } else { stamp.tm_year = (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 + (tm->data[2] - '0') * 10 + (tm->data[3] - '0'); stamp.tm_year -= 1900; offset = 2; } } stamp.tm_mon = (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1; stamp.tm_mday = (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0'); stamp.tm_hour = (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0'); stamp.tm_min = (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0'); stamp.tm_sec = (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0'); stamp.tm_isdst = -1; time_left = difftime(timegm(&stamp), time(NULL)); days_left = time_left / 86400; tm_t = mktime (&stamp); strftime(timestamp, 50, "%c", localtime(&tm_t)); if (days_left > 0 && days_left <= days_till_exp_warn) { printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, days_left, timestamp); if (days_left > days_till_exp_crit) status = STATE_WARNING; else status = STATE_CRITICAL; } else if (days_left == 0 && time_left > 0) { if (time_left >= 3600) time_remaining = (int) time_left / 3600; else time_remaining = (int) time_left / 60; printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp); if ( days_left > days_till_exp_crit) status = STATE_WARNING; else status = STATE_CRITICAL; } else if (time_left < 0) { printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp); status=STATE_CRITICAL; } else if (days_left == 0) { printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, timestamp); if (days_left > days_till_exp_crit) status = STATE_WARNING; else status = STATE_CRITICAL; } else { printf(_("OK - Certificate '%s' will expire on %s.\n"), cn, timestamp); status = STATE_OK; } X509_free(certificate); return status; # else /* ifndef USE_OPENSSL */ printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); return STATE_WARNING; # endif /* USE_OPENSSL */ }
//construct an SSL connection to the server at the desired address //gives back a struct containing the BIO and SSL constructs necessary //to manage a connection. // //Requires a directory where require certificates and public keys are stored and their names struct ssl_connection * connect_to(char *address, char *certpath, char *cacert, char *cert, char *privkey) { struct ssl_connection *conn = calloc(1, sizeof *conn); //BIO *bio; //SSL *ssl; SSL_CTX *ctx = (SSL_CTX *)SSL_CTX_new(SSLv23_client_method()); printf("LOADING CA CERT\n"); //load our ca certificate if(SSL_CTX_load_verify_locations(ctx, string_cat(3,certpath,"/",cacert), NULL) == 0) { printf("FAILING\n"); ssl_error("Server cert load fail"); exit(1); } printf("LOADING CLIENT CERT\n"); //load our certificate used to send files if(SSL_CTX_use_certificate_file(ctx, string_cat(3,certpath,"/",cert), SSL_FILETYPE_PEM) < 1) { ssl_error("failed to load client cert"); exit(1); } printf("LOADING PRIVATE KEY\n"); //load our private key if(SSL_CTX_use_PrivateKey_file(ctx, string_cat(3,certpath,"/",privkey), SSL_FILETYPE_PEM) < 1) { ssl_error("failed to load private key"); exit(1); } SSL_CTX_set_timeout(ctx, 5); conn->bio = BIO_new_ssl_connect(ctx); if(conn->bio == NULL) { ssl_error("bio creation fail"); exit(1); } //set up connection BIO_get_ssl(conn->bio, &conn->ssl); SSL_set_mode(conn->ssl, SSL_MODE_AUTO_RETRY); SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); //client stuff goes here //set server hostname if(BIO_set_conn_hostname(conn->bio, address) <= 0) { printf("Address error\n"); ssl_error("BIO connect error"); exit(1); } //printf("attempting to connect to %s\n",address); //test connection if(BIO_do_connect(conn->bio) <= 0) { printf("CONNECTION ERROR!?!?!?\n"); ssl_error("BIO connect error"); exit(1); } //verify the certificate if(BIO_do_handshake(conn->bio) > 0) { //printf("HANDSHAKE SUCCESS\n"); if(SSL_get_verify_result(conn->ssl) == X509_V_OK) { X509 *server_cert = SSL_get_peer_certificate(conn->ssl); if(server_cert == NULL) { printf("Didn't get a server certificate\n"); return NULL; } return conn; } else printf("CANNOT VERIFY SERVER CERTIFICATE! SHUTTING DOWN!!!\n"); } else printf("HANDSHAKE FAIL\n"); return NULL; //FAILURE }
bool SSLSocket::waitWant(int ret, uint64_t millis) { #ifdef HEADER_OPENSSLV_H int err = SSL_get_error(ssl, ret); switch(err) { case SSL_ERROR_WANT_READ: return wait(millis, Socket::WAIT_READ) == WAIT_READ; case SSL_ERROR_WANT_WRITE: return wait(millis, Socket::WAIT_WRITE) == WAIT_WRITE; #else int err = ssl->last_error; switch(err) { case GNUTLS_E_INTERRUPTED: case GNUTLS_E_AGAIN: { int waitFor = wait(millis, Socket::WAIT_READ | Socket::WAIT_WRITE); return (waitFor & Socket::WAIT_READ) || (waitFor & Socket::WAIT_WRITE); } #endif // Check if this is a fatal error... default: checkSSL(ret); } dcdebug("SSL: Unexpected fallthrough"); // There was no error? return true; } int SSLSocket::read(void* aBuffer, int aBufLen) throw(SocketException) { if(!ssl) { return -1; } int len = checkSSL(SSL_read(ssl, aBuffer, aBufLen)); if(len > 0) { stats.totalDown += len; //dcdebug("In(s): %.*s\n", len, (char*)aBuffer); } return len; } int SSLSocket::write(const void* aBuffer, int aLen) throw(SocketException) { if(!ssl) { return -1; } int ret = checkSSL(SSL_write(ssl, aBuffer, aLen)); if(ret > 0) { stats.totalUp += ret; //dcdebug("Out(s): %.*s\n", ret, (char*)aBuffer); } return ret; } int SSLSocket::checkSSL(int ret) throw(SocketException) { if(!ssl) { return -1; } if(ret <= 0) { int err = SSL_get_error(ssl, ret); switch(err) { case SSL_ERROR_NONE: // Fallthrough - YaSSL doesn't for example return an openssl compatible error on recv fail case SSL_ERROR_WANT_READ: // Fallthrough case SSL_ERROR_WANT_WRITE: return -1; case SSL_ERROR_ZERO_RETURN: #ifndef HEADER_OPENSSLV_H if(ssl->last_error == GNUTLS_E_INTERRUPTED || ssl->last_error == GNUTLS_E_AGAIN) return -1; #endif throw SocketException(STRING(CONNECTION_CLOSED)); default: { ssl.reset(); // @todo replace 80 with MAX_ERROR_SZ or whatever's appropriate for yaSSL in some nice way... char errbuf[80]; /* TODO: better message for SSL_ERROR_SYSCALL * If the error queue is empty (i.e. ERR_get_error() returns 0), ret can be used to find out more about the error: * If ret == 0, an EOF was observed that violates the protocol. If ret == -1, the underlying BIO reported an I/O error * (for socket I/O on Unix systems, consult errno for details). */ int error = ERR_get_error(); sprintf(errbuf, "%s %d: %s", CSTRING(SSL_ERROR), err, (error == 0) ? CSTRING(CONNECTION_CLOSED) : ERR_reason_error_string(error)); throw SSLSocketException(errbuf); } } } return ret; } int SSLSocket::wait(uint64_t millis, int waitFor) throw(SocketException) { #ifdef HEADER_OPENSSLV_H if(ssl && (waitFor & Socket::WAIT_READ)) { /** @todo Take writing into account as well if reading is possible? */ char c; if(SSL_peek(ssl, &c, 1) > 0) return WAIT_READ; } #endif return Socket::wait(millis, waitFor); } bool SSLSocket::isTrusted() throw() { if(!ssl) { return false; } #ifdef HEADER_OPENSSLV_H if(SSL_get_verify_result(ssl) != X509_V_OK) { return false; } #else if(gnutls_certificate_verify_peers(((SSL*)ssl)->gnutls_state) != 0) { return false; } #endif X509* cert = SSL_get_peer_certificate(ssl); if(!cert) { return false; } X509_free(cert); return true; } std::string SSLSocket::getCipherName() throw() { if(!ssl) return Util::emptyString; return SSL_get_cipher_name(ssl); } std::string SSLSocket::getDigest() const throw() { #ifdef HEADER_OPENSSLV_H if(!ssl) return Util::emptyString; X509* x509 = SSL_get_peer_certificate(ssl); if(!x509) return Util::emptyString; return ssl::X509_digest(x509, EVP_sha1()); #else return Util::emptyString; #endif } void SSLSocket::shutdown() throw() { if(ssl) SSL_shutdown(ssl); } void SSLSocket::close() throw() { if(ssl) { ssl.reset(); } Socket::shutdown(); Socket::close(); } } // namespace dcpp
/*********************parent process tcp connection use to manage************************/ void client_mgr(char *ip, int serverPort, int pipefd, int pid) { int flag = 0; char *p; char name[256], passwd[256]; char realName[512]; int err, fd, i; struct sockaddr_in sa; char buf[4096]; SSL_CTX* ctx; SSL* ssl; //create a TCP socket fd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR(fd, "socket"); memset (&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(ip); sa.sin_port = htons(serverPort); //connect step err = connect(fd, (struct sockaddr*) &sa, sizeof(sa)); CHK_ERR(err, "connect"); sleep(2); puts("Please input the common name: "); scanf("%s", realName); setupCTX(&ctx); //build SSL on the TCP connection ssl = SSL_new(ctx); CHK_NULL(ssl); SSL_set_fd (ssl, fd); err = SSL_connect(ssl); CHK_SSL(err); //check certificate SSL_CTX_load_verify_locations(ctx, CACERT, NULL); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); int result = SSL_get_verify_result(ssl); if(result == X509_V_OK || result == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) { printf("The certificate is valid.\n"); } else { printf("Invalid certificate %d\n", result); exit(1); } X509* server_cert = SSL_get_peer_certificate(ssl); CHK_NULL(server_cert); char *str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0); CHK_NULL(str); OPENSSL_free(str); str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0); CHK_NULL(str); OPENSSL_free(str); X509_NAME *xname = X509_get_subject_name(server_cert); X509_NAME_get_text_by_NID(xname, NID_commonName, commonName, 512); if( strcasecmp(commonName, realName) !=0 ) { printf("commonName is wrong.\n"); exit(1); } printf("commonName is right.\n"); printf("Server authentication is successful.\n"); //release! X509_free(server_cert); sleep(2); while(!flag) { //handle the login part printf("username: "******"%s",name); getchar(); //safe mode set_disp_mode(STDIN_FILENO, 0); getpasswd(passwd, sizeof(passwd)); p = passwd; while(*p != '\n') p++; *p = '\0'; //OK! set_disp_mode(STDIN_FILENO, 1); sendName(ssl, name); sendPass(ssl, passwd); SSL_read(ssl, buf, sizeof(buf) - 1); putchar(10); if( buf[0] == 'o' ) { puts("Connect successfully"); flag = 1; } else { puts("wrong password, please try again!"); } } //clean the password for security reason memset(passwd, 0, sizeof(passwd)); genKey(key); sendKey(ssl, key); while (1) { talkToudp(key, pipefd, 'k'); printf("1. ipnut 'q' to quit.\n"); printf("2. input 'c' to change the key.\n"); scanf("%s", buf); if (strlen(buf) == 1) { if (buf[0]=='q') { break; } else if( buf[0]=='r'){ genKey(key); sendKey(ssl, key); } } else { printf("Invalid.\n"); continue; } } memset(key, 0, KEYSIZE); memset(IV, 0, IVSIZE); sendKey(ssl, key); sleep(1); kill(pid, SIGTERM); wait(0); SSL_shutdown(ssl); /* send SSL/TLS close_notify */ close(fd); SSL_free(ssl); SSL_CTX_free(ctx); }
static int amqp_ssl_socket_open(void *base, const char *host, int port, struct timeval *timeout) { struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; long result; int status; amqp_time_t deadline; X509 *cert; BIO *bio; if (-1 != self->sockfd) { return AMQP_STATUS_SOCKET_INUSE; } ERR_clear_error(); self->ssl = SSL_new(self->ctx); if (!self->ssl) { self->internal_error = ERR_peek_error(); status = AMQP_STATUS_SSL_ERROR; goto exit; } status = amqp_time_from_now(&deadline, timeout); if (AMQP_STATUS_OK != status) { return status; } self->sockfd = amqp_open_socket_inner(host, port, deadline); if (0 > self->sockfd) { status = self->sockfd; self->internal_error = amqp_os_socket_error(); self->sockfd = -1; goto error_out1; } bio = BIO_new(amqp_openssl_bio()); if (!bio) { status = AMQP_STATUS_NO_MEMORY; goto error_out2; } BIO_set_fd(bio, self->sockfd, BIO_NOCLOSE); SSL_set_bio(self->ssl, bio, bio); start_connect: status = SSL_connect(self->ssl); if (status != 1) { self->internal_error = SSL_get_error(self->ssl, status); switch (self->internal_error) { case SSL_ERROR_WANT_READ: status = amqp_poll(self->sockfd, AMQP_SF_POLLIN, deadline); break; case SSL_ERROR_WANT_WRITE: status = amqp_poll(self->sockfd, AMQP_SF_POLLOUT, deadline); break; default: status = AMQP_STATUS_SSL_CONNECTION_FAILED; } if (AMQP_STATUS_OK == status) { goto start_connect; } goto error_out2; } cert = SSL_get_peer_certificate(self->ssl); if (self->verify_peer) { if (!cert) { self->internal_error = 0; status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED; goto error_out3; } result = SSL_get_verify_result(self->ssl); if (X509_V_OK != result) { self->internal_error = result; status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED; goto error_out4; } } if (self->verify_hostname) { if (!cert) { self->internal_error = 0; status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED; goto error_out3; } if (AMQP_HVR_MATCH_FOUND != amqp_ssl_validate_hostname(host, cert)) { self->internal_error = 0; status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED; goto error_out4; } } X509_free(cert); self->internal_error = 0; status = AMQP_STATUS_OK; exit: return status; error_out4: X509_free(cert); error_out3: SSL_shutdown(self->ssl); error_out2: amqp_os_socket_close(self->sockfd); self->sockfd = -1; error_out1: SSL_free(self->ssl); self->ssl = NULL; goto exit; }
NOEXPORT int connect_local(CLI *c) { /* spawn local process */ char *name, host[40]; int fd[2], pid; X509 *peer; #ifdef HAVE_PTHREAD_SIGMASK sigset_t newmask; #endif if(c->opt->option.pty) { char tty[64]; if(pty_allocate(fd, fd+1, tty)) longjmp(c->err, 1); s_log(LOG_DEBUG, "TTY=%s allocated", tty); } else if(make_sockets(fd)) longjmp(c->err, 1); pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1: /* error */ closesocket(fd[0]); closesocket(fd[1]); ioerror("fork"); longjmp(c->err, 1); case 0: /* child */ closesocket(fd[0]); set_nonblock(fd[1], 0); /* switch back to blocking mode */ /* dup2() does not copy FD_CLOEXEC flag */ dup2(fd[1], 0); dup2(fd[1], 1); if(!global_options.option.foreground) dup2(fd[1], 2); closesocket(fd[1]); /* not really needed due to FD_CLOEXEC */ if(!getnameinfo(&c->peer_addr.sa, c->peer_addr_len, host, 40, NULL, 0, NI_NUMERICHOST)) { /* just don't set these variables if getnameinfo() fails */ putenv(str_printf("REMOTE_HOST=%s", host)); if(c->opt->option.transparent_src) { #ifndef LIBDIR #define LIBDIR "." #endif #ifdef MACH64 putenv("LD_PRELOAD_32=" LIBDIR "/libstunnel.so"); putenv("LD_PRELOAD_64=" LIBDIR "/" MACH64 "/libstunnel.so"); #elif __osf /* for Tru64 _RLD_LIST is used instead */ putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); #else putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so"); #endif } } if(c->ssl) { peer=SSL_get_peer_certificate(c->ssl); if(peer) { name=X509_NAME_oneline(X509_get_subject_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_DN=%s", name)); name=X509_NAME_oneline(X509_get_issuer_name(peer), NULL, 0); safestring(name); putenv(str_printf("SSL_CLIENT_I_DN=%s", name)); X509_free(peer); } } #ifdef HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); sigprocmask(SIG_SETMASK, &newmask, NULL); #endif signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGUSR1, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); execvp(c->opt->execname, c->opt->execargs); ioerror(c->opt->execname); /* execvp failed */ _exit(1); default: /* parent */ s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid); closesocket(fd[1]); return fd[0]; } }
/* * Attempt to negotiate SSL connection. */ int be_tls_open_server(Port *port) { int r; int err; int waitfor; unsigned long ecode; Assert(!port->ssl); Assert(!port->peer); if (!(port->ssl = SSL_new(SSL_context))) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not initialize SSL connection: %s", SSLerrmessage(ERR_get_error())))); return -1; } if (!my_SSL_set_fd(port, port->sock)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not set SSL socket: %s", SSLerrmessage(ERR_get_error())))); return -1; } port->ssl_in_use = true; aloop: /* * Prepare to call SSL_get_error() by clearing thread's OpenSSL error * queue. In general, the current thread's error queue must be empty * before the TLS/SSL I/O operation is attempted, or SSL_get_error() * will not work reliably. An extension may have failed to clear the * per-thread error queue following another call to an OpenSSL I/O * routine. */ ERR_clear_error(); r = SSL_accept(port->ssl); if (r <= 0) { err = SSL_get_error(port->ssl, r); /* * Other clients of OpenSSL in the backend may fail to call * ERR_get_error(), but we always do, so as to not cause problems * for OpenSSL clients that don't call ERR_clear_error() * defensively. Be sure that this happens by calling now. * SSL_get_error() relies on the OpenSSL per-thread error queue * being intact, so this is the earliest possible point * ERR_get_error() may be called. */ ecode = ERR_get_error(); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* not allowed during connection establishment */ Assert(!port->noblock); /* * No need to care about timeouts/interrupts here. At this * point authentication_timeout still employs * StartupPacketTimeoutHandler() which directly exits. */ if (err == SSL_ERROR_WANT_READ) waitfor = WL_SOCKET_READABLE; else waitfor = WL_SOCKET_WRITEABLE; WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0); goto aloop; case SSL_ERROR_SYSCALL: if (r < 0) ereport(COMMERROR, (errcode_for_socket_access(), errmsg("could not accept SSL connection: %m"))); else ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not accept SSL connection: EOF detected"))); break; case SSL_ERROR_SSL: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not accept SSL connection: %s", SSLerrmessage(ecode)))); break; case SSL_ERROR_ZERO_RETURN: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not accept SSL connection: EOF detected"))); break; default: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unrecognized SSL error code: %d", err))); break; } return -1; } port->count = 0; /* Get client certificate, if available. */ port->peer = SSL_get_peer_certificate(port->ssl); /* and extract the Common Name from it. */ port->peer_cn = NULL; port->peer_cert_valid = false; if (port->peer != NULL) { int len; len = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), NID_commonName, NULL, 0); if (len != -1) { char *peer_cn; peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1); r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), NID_commonName, peer_cn, len + 1); peer_cn[len] = '\0'; if (r != len) { /* shouldn't happen */ pfree(peer_cn); return -1; } /* * Reject embedded NULLs in certificate common name to prevent * attacks like CVE-2009-4034. */ if (len != strlen(peer_cn)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL certificate's common name contains embedded null"))); pfree(peer_cn); return -1; } port->peer_cn = peer_cn; } port->peer_cert_valid = true; } ereport(DEBUG2, (errmsg("SSL connection from \"%s\"", port->peer_cn ? port->peer_cn : "(anonymous)"))); /* set up debugging/info callback */ SSL_CTX_set_info_callback(SSL_context, info_cb); return 0; }
/* this is called after the connection on the client side by us to check other aspects about the connection */ int netsnmp_tlsbase_verify_server_cert(SSL *ssl, _netsnmpTLSBaseData *tlsdata) { /* XXX */ X509 *remote_cert; char *check_name; int ret; netsnmp_assert_or_return(ssl != NULL, SNMPERR_GENERR); netsnmp_assert_or_return(tlsdata != NULL, SNMPERR_GENERR); if (NULL == (remote_cert = SSL_get_peer_certificate(ssl))) { /* no peer cert */ DEBUGMSGTL(("tls_x509:verify", "remote connection provided no certificate (yet)\n")); return SNMPERR_TLS_NO_CERTIFICATE; } /* make sure that the fingerprint matches */ ret = _netsnmp_tlsbase_verify_remote_fingerprint(remote_cert, tlsdata, 1); switch(ret) { case VERIFIED_FINGERPRINT: return SNMPERR_SUCCESS; case FAILED_FINGERPRINT_VERIFY: return SNMPERR_GENERR; case NO_FINGERPRINT_AVAILABLE: if (tlsdata->their_hostname && tlsdata->their_hostname[0] != '\0') { GENERAL_NAMES *onames; const GENERAL_NAME *oname = NULL; int i, j; int count; char buf[SPRINT_MAX_LEN]; int is_wildcarded = 0; char *compare_to; /* see if the requested hostname has a wildcard prefix */ if (strncmp(tlsdata->their_hostname, "*.", 2) == 0) { is_wildcarded = 1; compare_to = tlsdata->their_hostname + 2; } else { compare_to = tlsdata->their_hostname; } /* if the hostname we were expecting to talk to matches the cert, then we can accept this connection. */ /* check against the DNS subjectAltName */ onames = (GENERAL_NAMES *)X509_get_ext_d2i(remote_cert, NID_subject_alt_name, NULL, NULL ); if (NULL != onames) { count = sk_GENERAL_NAME_num(onames); for (i=0 ; i <count; ++i) { oname = sk_GENERAL_NAME_value(onames, i); if (GEN_DNS == oname->type) { /* get the value */ ASN1_STRING_to_UTF8((unsigned char**)&check_name, oname->d.ia5); /* convert to lowercase for comparisons */ for (j = 0 ; *check_name && j < sizeof(buf)-1; ++check_name, ++j ) { if (isascii(*check_name)) buf[j] = tolower(0xFF & *check_name); } if (j < sizeof(buf)) buf[j] = '\0'; check_name = buf; if (is_wildcarded) { /* we *only* allow passing till the first '.' */ /* ie *.example.com can't match a.b.example.com */ check_name = strchr(check_name, '.') + 1; } DEBUGMSGTL(("tls_x509:verify", "checking subjectAltname of dns:%s\n", check_name)); if (strcmp(compare_to, check_name) == 0) { DEBUGMSGTL(("tls_x509:verify", "Successful match on a subjectAltname of dns:%s\n", check_name)); return SNMPERR_SUCCESS; } } } } /* check the common name for a match */ check_name = netsnmp_openssl_cert_get_commonName(remote_cert, NULL, NULL); if (is_wildcarded) { /* we *only* allow passing till the first '.' */ /* ie *.example.com can't match a.b.example.com */ check_name = strchr(check_name, '.') + 1; } if (strcmp(compare_to, check_name) == 0) { DEBUGMSGTL(("tls_x509:verify", "Successful match on a common name of %s\n", check_name)); return SNMPERR_SUCCESS; } snmp_log(LOG_ERR, "No matching names in the certificate to match the expected %s\n", tlsdata->their_hostname); return SNMPERR_GENERR; } /* XXX: check for hostname match instead */ snmp_log(LOG_ERR, "Can not verify a remote server identity without configuration\n"); return SNMPERR_GENERR; } DEBUGMSGTL(("tls_x509:verify", "shouldn't get here\n")); return SNMPERR_GENERR; }
/* * This is the actual startup routine for the connection. We expect that the * buffers are flushed and the "220 Ready to start TLS" was received by us, * so that we can immediately start the TLS handshake process. */ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) { int sts; int protomask; const char *cipher_list; SSL_SESSION *session = 0; SSL_CIPHER_const SSL_CIPHER *cipher; X509 *peercert; TLS_SESS_STATE *TLScontext; TLS_APPL_STATE *app_ctx = props->ctx; char *myserverid; int log_mask = app_ctx->log_mask; /* * When certificate verification is required, log trust chain validation * errors even when disabled by default for opportunistic sessions. For * DANE this only applies when using trust-anchor associations. */ if (TLS_MUST_TRUST(props->tls_level) && (!TLS_DANE_BASED(props->tls_level) || TLS_DANE_HASTA(props->dane))) log_mask |= TLS_LOG_UNTRUSTED; if (log_mask & TLS_LOG_VERBOSE) msg_info("setting up TLS connection to %s", props->namaddr); /* * First make sure we have valid protocol and cipher parameters * * Per-session protocol restrictions must be applied to the SSL connection, * as restrictions in the global context cannot be cleared. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session", props->namaddr, props->protocols); return (0); } /* DANE requires SSLv3 or later, not SSLv2. */ if (TLS_DANE_BASED(props->tls_level)) protomask |= TLS_PROTOCOL_SSLv2; /* * Per session cipher selection for sessions with mandatory encryption * * The cipherlist is applied to the global SSL context, since it is likely * to stay the same between connections, so we make use of a 1-element * cache to return the same result for identical inputs. */ cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { msg_warn("%s: %s: aborting TLS session", props->namaddr, vstring_str(app_ctx->why)); return (0); } if (log_mask & TLS_LOG_VERBOSE) msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); /* * OpenSSL will ignore cached sessions that use the wrong protocol. So we * do not need to filter out cached sessions with the "wrong" protocol, * rather OpenSSL will simply negotiate a new session. * * We salt the session lookup key with the protocol list, so that sessions * found in the cache are plausibly acceptable. * * By the time a TLS client is negotiating ciphers it has already offered to * re-use a session, it is too late to renege on the offer. So we must * not attempt to re-use sessions whose ciphers are too weak. We salt the * session lookup key with the cipher list, so that sessions found in the * cache are always acceptable. * * With DANE, (more generally any TLScontext where we specified explicit * trust-anchor or end-entity certificates) the verification status of * the SSL session depends on the specified list. Since we verify the * certificate only during the initial handshake, we must segregate * sessions with different TA lists. Note, that TA re-verification is * not possible with cached sessions, since these don't hold the complete * peer trust chain. Therefore, we compute a digest of the sorted TA * parameters and append it to the serverid. */ myserverid = tls_serverid_digest(props, protomask, cipher_list); /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve * the information inside the tls_verify_certificate_callback(). * * If session caching was enabled when TLS was initialized, the cache type * is stored in the client SSL context. */ TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; TLScontext->serverid = myserverid; TLScontext->stream = props->stream; TLScontext->mdalg = props->mdalg; /* Alias DANE digest info from props */ TLScontext->dane = props->dane; if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); tls_print_errors(); tls_free_context(TLScontext); return (0); } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * Apply session protocol restrictions. */ if (protomask != 0) SSL_set_options(TLScontext->con, TLS_SSL_OP_PROTOMASK(protomask)); #ifdef SSL_SECOP_PEER /* When authenticating the peer, use 80-bit plus OpenSSL security level */ if (TLS_MUST_MATCH(props->tls_level)) SSL_set_security_level(TLScontext->con, 1); #endif /* * XXX To avoid memory leaks we must always call SSL_SESSION_free() after * calling SSL_set_session(), regardless of whether or not the session * will be reused. */ if (TLScontext->cache_type) { session = load_clnt_session(TLScontext); if (session) { SSL_set_session(TLScontext->con, session); SSL_SESSION_free(session); /* 200411 */ } } #ifdef TLSEXT_MAXLEN_host_name if (TLS_DANE_BASED(props->tls_level) && strlen(props->host) <= TLSEXT_MAXLEN_host_name) { /* * With DANE sessions, send an SNI hint. We don't care whether the * server reports finding a matching certificate or not, so no * callback is required to process the server response. Our use of * SNI is limited to giving servers that are (mis)configured to use * SNI the best opportunity to find the certificate they promised via * the associated TLSA RRs. (Generally, server administrators should * avoid SNI, and there are no plans to support SNI in the Postfix * SMTP server). * * Since the hostname is DNSSEC-validated, it must be a DNS FQDN and * thererefore valid for use with SNI. Failure to set a valid SNI * hostname is a memory allocation error, and thus transient. Since * we must not cache the session if we failed to send the SNI name, * we have little choice but to abort. */ if (!SSL_set_tlsext_host_name(TLScontext->con, props->host)) { msg_warn("%s: error setting SNI hostname to: %s", props->namaddr, props->host); tls_free_context(TLScontext); return (0); } if (log_mask & TLS_LOG_DEBUG) msg_info("%s: SNI hostname: %s", props->namaddr, props->host); } #endif /* * Before really starting anything, try to seed the PRNG a little bit * more. */ tls_int_seed(); (void) tls_ext_seed(var_tls_daemon_rand_bytes); /* * Initialize the SSL connection to connect state. This should not be * necessary anymore since 0.9.3, but the call is still in the library * and maintaining compatibility never hurts. */ SSL_set_connect_state(TLScontext->con); /* * Connect the SSL connection with the network socket. */ if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) { msg_info("SSL_set_fd error to %s", props->namaddr); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* * Turn on non-blocking I/O so that we can enforce timeouts on network * I/O. */ non_blocking(vstream_fileno(props->stream), NON_BLOCKING); /* * If the debug level selected is high enough, all of the data is dumped: * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will * dump everything. * * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? * Well there is a BIO below the SSL routines that is automatically * created for us, so we can use it for debugging purposes. */ if (log_mask & TLS_LOG_TLSPKTS) BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext); /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for certificate verification. * * Error handling: If the SSL handhake fails, we print out an error message * and remove all TLS state concerning this session. */ sts = tls_bio_connect(vstream_fileno(props->stream), props->timeout, TLScontext); if (sts <= 0) { if (ERR_peek_error() != 0) { msg_info("SSL_connect error to %s: %d", props->namaddr, sts); tls_print_errors(); } else if (errno != 0) { msg_info("SSL_connect error to %s: %m", props->namaddr); } else { msg_info("SSL_connect error to %s: lost connection", props->namaddr); } uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* Turn off packet dump if only dumping the handshake */ if ((log_mask & TLS_LOG_ALLPKTS) == 0) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* * The caller may want to know if this session was reused or if a new * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) msg_info("%s: Reusing old session", TLScontext->namaddr); /* * Do peername verification if requested and extract useful information * from the certificate for later use. */ if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) { TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; /* * Peer name or fingerprint verification as requested. * Unconditionally set peer_CN, issuer_CN and peer_cert_fprint. Check * fingerprint first, and avoid logging verified as untrusted in the * call to verify_extract_name(). */ verify_extract_print(TLScontext, peercert, props); verify_extract_name(TLScontext, peercert, props); if (TLScontext->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT)) msg_info("%s: subject_CN=%s, issuer_CN=%s, " "fingerprint=%s, pkey_fingerprint=%s", props->namaddr, TLScontext->peer_CN, TLScontext->issuer_CN, TLScontext->peer_cert_fprint, TLScontext->peer_pkey_fprint); X509_free(peercert); } else { TLScontext->issuer_CN = mystrdup(""); TLScontext->peer_CN = mystrdup(""); TLScontext->peer_cert_fprint = mystrdup(""); TLScontext->peer_pkey_fprint = mystrdup(""); } /* * Finally, collect information about protocol and cipher for logging */ TLScontext->protocol = SSL_get_version(TLScontext->con); cipher = SSL_get_current_cipher(TLScontext->con); TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, &(TLScontext->cipher_algbits)); /* * The TLS engine is active. Switch to the tls_timed_read/write() * functions and make the TLScontext available to those functions. */ tls_stream_start(props->stream, TLScontext); /* * Fully secured only if trusted, matched and not insecure like halfdane. * Should perhaps also exclude "verify" (as opposed to "secure") here, * because that can be subject to insecure MX indirection, but that's * rather incompatible. Users have been warned. */ if (TLS_CERT_IS_PRESENT(TLScontext) && TLS_CERT_IS_TRUSTED(TLScontext) && TLS_CERT_IS_MATCHED(TLScontext) && !TLS_NEVER_SECURED(props->tls_level)) TLScontext->peer_status |= TLS_CERT_FLAG_SECURED; /* * All the key facts in a single log entry. */ if (log_mask & TLS_LOG_SUMMARY) msg_info("%s TLS connection established to %s: %s with cipher %s " "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" : TLS_CERT_IS_SECURED(TLScontext) ? "Verified" : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", props->namaddr, TLScontext->protocol, TLScontext->cipher_name, TLScontext->cipher_usebits, TLScontext->cipher_algbits); tls_int_seed(); return (TLScontext); }
int main () { int err; int sd; struct sockaddr_in sa; SSL_CTX* ctx; SSL* ssl; X509* server_cert; char* str; char buf [4096]; SSL_METHOD *meth; SSLeay_add_ssl_algorithms(); //设置支持SSL算法 meth = (SSL_METHOD*)SSLv2_client_method(); //客户端设置SSLV2版本 SSL_load_error_strings(); //提供将错误解析为字符串的功能 ctx = SSL_CTX_new (meth); CHK_NULL(ctx); //创建一个SSL上下文环境,每个进程守护一个SSL_CTX结构体 CHK_SSL(err); /* ----------------------------------------------- */ /* Create a socket and connect to server using normal socket calls. */ sd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR(sd, "socket"); // memset (&sa, '\0', sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr ("127.0.0.1"); /* Server IP */ sa.sin_port = htons (1111); /* Server Port number */ err = connect(sd, (struct sockaddr*) &sa, sizeof(sa)); CHK_ERR(err, "connect"); /* ----------------------------------------------- */ /* Now we have TCP conncetion. Start SSL negotiation. */ //创建一个维护当前连接信息 ssl = SSL_new (ctx); CHK_NULL(ssl); //将SSL绑定到套接字上 SSL_set_fd (ssl, sd); //建立SSL连接 err = SSL_connect (ssl); CHK_SSL(err); /* Following two steps are optional and not required for data exchange to be successful. */ /* Get the cipher - opt */ printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); /* Get server's certificate (note: beware of dynamic allocation) - opt */ //获取服务端证书 server_cert = SSL_get_peer_certificate (ssl); CHK_NULL(server_cert); printf ("Server certificate:\n"); str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0); CHK_NULL(str); printf ("\t subject: %s\n", str); OPENSSL_free (str); str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0); CHK_NULL(str); printf ("\t issuer: %s\n", str); OPENSSL_free (str); /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ //释放服务端证书 X509_free (server_cert); /* --------------------------------------------------- */ /* DATA EXCHANGE - Send a message and receive a reply. */ err = SSL_write (ssl, "Hello World!", strlen("Hello World!")); CHK_SSL(err); err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err); buf[err] = '\0'; printf ("Got %d chars:'%s'\n", err, buf); SSL_shutdown (ssl); /* send SSL/TLS close_notify */ /* Clean up. */ close(sd); SSL_free (ssl); SSL_CTX_free (ctx); }
int OpenSSLVerifyCertificate(STREAM *S) { int RetVal=FALSE; #ifdef HAVE_LIBSSL char *Name=NULL, *Value=NULL, *ptr; int val; X509 *cert=NULL; SSL *ssl; ptr=STREAMGetItem(S,"LIBUSEFUL-SSL-CTX"); if (! ptr) return(FALSE); ssl=(SSL *) ptr; cert=SSL_get_peer_certificate(ssl); if (cert) { STREAMSetValue(S,"SSL-Certificate-Issuer",X509_NAME_oneline( X509_get_issuer_name(cert),NULL, 0)); ptr=X509_NAME_oneline( X509_get_subject_name(cert),NULL, 0); STREAMSetValue(S,"SSL-Certificate-Subject", ptr); ptr=GetNameValuePair(ptr,"/","=",&Name,&Value); while (ptr) { if (StrLen(Name) && (strcmp(Name,"CN")==0)) STREAMSetValue(S,"SSL-Certificate-CommonName",Value); ptr=GetNameValuePair(ptr,"/","=",&Name,&Value); } val=SSL_get_verify_result(ssl); switch(val) { case X509_V_OK: STREAMSetValue(S,"SSL-Certificate-Verify","OK"); RetVal=TRUE; break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: STREAMSetValue(S,"SSL-Certificate-Verify","unable to get issuer"); break; case X509_V_ERR_UNABLE_TO_GET_CRL: STREAMSetValue(S,"SSL-Certificate-Verify","unable to get certificate CRL"); break; case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: STREAMSetValue(S,"SSL-Certificate-Verify","unable to decrypt certificate's signature"); break; case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: STREAMSetValue(S,"SSL-Certificate-Verify","unable to decrypt CRL's signature"); break; case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: STREAMSetValue(S,"SSL-Certificate-Verify","unable to decode issuer public key"); break; case X509_V_ERR_CERT_SIGNATURE_FAILURE: STREAMSetValue(S,"SSL-Certificate-Verify","certificate signature invalid"); break; case X509_V_ERR_CRL_SIGNATURE_FAILURE: STREAMSetValue(S,"SSL-Certificate-Verify","CRL signature invalid"); break; case X509_V_ERR_CERT_NOT_YET_VALID: STREAMSetValue(S,"SSL-Certificate-Verify","certificate is not yet valid"); break; case X509_V_ERR_CERT_HAS_EXPIRED: STREAMSetValue(S,"SSL-Certificate-Verify","certificate has expired"); break; case X509_V_ERR_CRL_NOT_YET_VALID: STREAMSetValue(S,"SSL-Certificate-Verify","CRL is not yet valid the CRL is not yet valid."); break; case X509_V_ERR_CRL_HAS_EXPIRED: STREAMSetValue(S,"SSL-Certificate-Verify","CRL has expired the CRL has expired."); break; case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: STREAMSetValue(S,"SSL-Certificate-Verify","invalid notBefore value"); break; case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: STREAMSetValue(S,"SSL-Certificate-Verify","invalid notAfter value"); break; case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: STREAMSetValue(S,"SSL-Certificate-Verify","invalid CRL lastUpdate value"); break; case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: STREAMSetValue(S,"SSL-Certificate-Verify","invalid CRL nextUpdate value"); break; case X509_V_ERR_OUT_OF_MEM: STREAMSetValue(S,"SSL-Certificate-Verify","out of memory"); break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: STREAMSetValue(S,"SSL-Certificate-Verify","self signed certificate"); break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: STREAMSetValue(S,"SSL-Certificate-Verify","self signed certificate in certificate chain"); break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: STREAMSetValue(S,"SSL-Certificate-Verify","cant find root certificate in local database"); break; case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: STREAMSetValue(S,"SSL-Certificate-Verify","ERROR: unable to verify the first certificate"); break; case X509_V_ERR_CERT_CHAIN_TOO_LONG: STREAMSetValue(S,"SSL-Certificate-Verify","certificate chain too long"); break; case X509_V_ERR_CERT_REVOKED: STREAMSetValue(S,"SSL-Certificate-Verify","certificate revoked"); break; case X509_V_ERR_INVALID_CA: STREAMSetValue(S,"SSL-Certificate-Verify","invalid CA certificate"); break; case X509_V_ERR_PATH_LENGTH_EXCEEDED: STREAMSetValue(S,"SSL-Certificate-Verify","path length constraint exceeded"); break; case X509_V_ERR_INVALID_PURPOSE: STREAMSetValue(S,"SSL-Certificate-Verify","unsupported certificate purpose"); break; case X509_V_ERR_CERT_UNTRUSTED: STREAMSetValue(S,"SSL-Certificate-Verify","certificate not trusted"); break; case X509_V_ERR_CERT_REJECTED: STREAMSetValue(S,"SSL-Certificate-Verify","certificate rejected"); break; case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: STREAMSetValue(S,"SSL-Certificate-Verify","subject issuer mismatch"); break; case X509_V_ERR_AKID_SKID_MISMATCH: STREAMSetValue(S,"SSL-Certificate-Verify","authority and subject key identifier mismatch"); break; case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: STREAMSetValue(S,"SSL-Certificate-Verify","authority and issuer serial number mismatch"); break; case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: STREAMSetValue(S,"SSL-Certificate-Verify","key usage does not include certificate signing"); break; case X509_V_ERR_APPLICATION_VERIFICATION: STREAMSetValue(S,"SSL-Certificate-Verify","application verification failure"); break; } } else { STREAMSetValue(S,"SSL-Certificate-Verify","no certificate"); } DestroyString(Name); DestroyString(Value); #endif return(RetVal); }
static CURLcode cyassl_connect_step2(struct connectdata *conn, int sockindex) { int ret = -1; struct SessionHandle *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; conn->recv[sockindex] = cyassl_recv; conn->send[sockindex] = cyassl_send; /* Enable RFC2818 checks */ if(data->set.ssl.verifyhost) { ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name); if(ret == SSL_FAILURE) return CURLE_OUT_OF_MEMORY; } ret = SSL_connect(conssl->handle); if(ret != 1) { char error_buffer[CYASSL_MAX_ERROR_SZ]; int detail = SSL_get_error(conssl->handle, ret); if(SSL_ERROR_WANT_READ == detail) { conssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } else if(SSL_ERROR_WANT_WRITE == detail) { conssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } /* There is no easy way to override only the CN matching. * This will enable the override of both mismatching SubjectAltNames * as also mismatching CN fields */ else if(DOMAIN_NAME_MISMATCH == detail) { #if 1 failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", conn->host.dispname); return CURLE_PEER_FAILED_VERIFICATION; #else /* When the CyaSSL_check_domain_name() is used and you desire to continue * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0', * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only * way to do this is currently to switch the CyaSSL_check_domain_name() * in and out based on the 'data->set.ssl.verifyhost' value. */ if(data->set.ssl.verifyhost) { failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", conn->host.dispname); return CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, "\tsubject alt name(s) and/or common name do not match \"%s\"\n", conn->host.dispname); return CURLE_OK; } #endif } #if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ else if(ASN_NO_SIGNER_E == detail) { if(data->set.ssl.verifypeer) { failf(data, "\tCA signer not available for verification\n"); return CURLE_SSL_CACERT_BADFILE; } else { /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "CA signer not available for verification, " "continuing anyway\n"); } } #endif else { failf(data, "SSL_connect failed with error %d: %s", detail, ERR_error_string(detail, error_buffer)); return CURLE_SSL_CONNECT_ERROR; } } if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { X509 *x509; const char *x509_der; int x509_der_len; curl_X509certificate x509_parsed; curl_asn1Element *pubkey; CURLcode result; x509 = SSL_get_peer_certificate(conssl->handle); if(!x509) { failf(data, "SSL: failed retrieving server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len); if(!x509_der) { failf(data, "SSL: failed retrieving ASN.1 server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } memset(&x509_parsed, 0, sizeof x509_parsed); Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len); pubkey = &x509_parsed.subjectPublicKeyInfo; if(!pubkey->header || pubkey->end <= pubkey->header) { failf(data, "SSL: failed retrieving public key from server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } result = Curl_pin_peer_pubkey(data, data->set.str[STRING_SSL_PINNEDPUBLICKEY], (const unsigned char *)pubkey->header, (size_t)(pubkey->end - pubkey->header)); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } } conssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); return CURLE_OK; }
/* sqAcceptSSL: Start/continue an SSL server handshake. Arguments: handle - the SSL handle srcBuf - the input token sent by the remote peer srcLen - the size of the input token dstBuf - the output buffer for a new token dstLen - the size of the output buffer Returns: The size of the output token or an error code. */ sqInt sqAcceptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt dstLen) { int result, n; char peerName[256]; X509 *cert; sqSSL *ssl = sslFromHandle(handle); /* Verify state of session */ if(ssl == NULL || (ssl->state != SQSSL_UNUSED && ssl->state != SQSSL_ACCEPTING)) { return SQSSL_INVALID_STATE; } /* Establish initial connection */ if(ssl->state == SQSSL_UNUSED) { ssl->state = SQSSL_ACCEPTING; if(ssl->loglevel) printf("sqAcceptSSL: Setting up SSL\n"); if(!sqSetupSSL(ssl, 1)) return SQSSL_GENERIC_ERROR; if(ssl->loglevel) printf("sqAcceptSSL: setting accept state\n"); SSL_set_accept_state(ssl->ssl); } if(ssl->loglevel) printf("sqAcceptSSL: BIO_write %d bytes\n", srcLen); n = BIO_write(ssl->bioRead, srcBuf, srcLen); if(n < srcLen) { if(ssl->loglevel) printf("sqAcceptSSL: BIO_write wrote less than expected\n"); return SQSSL_GENERIC_ERROR; } if(n < 0) { if(ssl->loglevel) printf("sqAcceptSSL: BIO_write failed\n"); return SQSSL_GENERIC_ERROR; } if(ssl->loglevel) printf("sqAcceptSSL: SSL_accept\n"); result = SSL_accept(ssl->ssl); if(result <= 0) { int count = 0; int error = SSL_get_error(ssl->ssl, result); if(error != SSL_ERROR_WANT_READ) { if(ssl->loglevel) printf("sqAcceptSSL: SSL_accept failed\n"); ERR_print_errors_fp(stdout); return SQSSL_GENERIC_ERROR; } if(ssl->loglevel) printf("sqAcceptSSL: sqCopyBioSSL\n"); count = sqCopyBioSSL(ssl, ssl->bioWrite, dstBuf, dstLen); return count ? count : SQSSL_NEED_MORE_DATA; } /* We are connected. Verify the cert. */ ssl->state = SQSSL_CONNECTED; if(ssl->loglevel) printf("sqAcceptSSL: SSL_get_peer_certificate\n"); cert = SSL_get_peer_certificate(ssl->ssl); if(ssl->loglevel) printf("sqAcceptSSL: cert = %x\n", (int)cert); if(cert) { X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, peerName, sizeof(peerName)); if(ssl->loglevel) printf("sqAcceptSSL: peerName = %s\n", peerName); ssl->peerName = strdup(peerName); X509_free(cert); /* Check the result of verification */ result = SSL_get_verify_result(ssl->ssl); if(ssl->loglevel) printf("sqAcceptSSL: SSL_get_verify_result = %d\n", result); /* FIXME: Figure out the actual failure reason */ ssl->certFlags = result ? SQSSL_OTHER_ISSUE : SQSSL_OK; } else { ssl->certFlags = SQSSL_NO_CERTIFICATE; } return sqCopyBioSSL(ssl, ssl->bioWrite, dstBuf, dstLen); }
static int verify_server_cert(gitno_ssl *ssl, const char *host) { X509 *cert; X509_NAME *peer_name; ASN1_STRING *str; unsigned char *peer_cn = NULL; int matched = -1, type = GEN_DNS; GENERAL_NAMES *alts; struct in6_addr addr6; struct in_addr addr4; void *addr; int i = -1,j; if (SSL_get_verify_result(ssl->ssl) != X509_V_OK) { giterr_set(GITERR_SSL, "The SSL certificate is invalid"); return -1; } /* Try to parse the host as an IP address to see if it is */ if (p_inet_pton(AF_INET, host, &addr4)) { type = GEN_IPADD; addr = &addr4; } else { if(p_inet_pton(AF_INET6, host, &addr6)) { type = GEN_IPADD; addr = &addr6; } } cert = SSL_get_peer_certificate(ssl->ssl); /* Check the alternative names */ alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (alts) { int num; num = sk_GENERAL_NAME_num(alts); for (i = 0; i < num && matched != 1; i++) { const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i); const char *name = (char *) ASN1_STRING_data(gn->d.ia5); size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5); /* Skip any names of a type we're not looking for */ if (gn->type != type) continue; if (type == GEN_DNS) { /* If it contains embedded NULs, don't even try */ if (memchr(name, '\0', namelen)) continue; if (check_host_name(name, host) < 0) matched = 0; else matched = 1; } else if (type == GEN_IPADD) { /* Here name isn't so much a name but a binary representation of the IP */ matched = !!memcmp(name, addr, namelen); } } } GENERAL_NAMES_free(alts); if (matched == 0) goto cert_fail; if (matched == 1) return 0; /* If no alternative names are available, check the common name */ peer_name = X509_get_subject_name(cert); if (peer_name == NULL) goto on_error; if (peer_name) { /* Get the index of the last CN entry */ while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0) i = j; } if (i < 0) goto on_error; str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i)); if (str == NULL) goto on_error; /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */ if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) { int size = ASN1_STRING_length(str); if (size > 0) { peer_cn = OPENSSL_malloc(size + 1); GITERR_CHECK_ALLOC(peer_cn); memcpy(peer_cn, ASN1_STRING_data(str), size); peer_cn[size] = '\0'; } } else { int size = ASN1_STRING_to_UTF8(&peer_cn, str); GITERR_CHECK_ALLOC(peer_cn); if (memchr(peer_cn, '\0', size)) goto cert_fail; } if (check_host_name((char *)peer_cn, host) < 0) goto cert_fail; OPENSSL_free(peer_cn); return 0; on_error: OPENSSL_free(peer_cn); return ssl_set_error(ssl, 0); cert_fail: OPENSSL_free(peer_cn); giterr_set(GITERR_SSL, "Certificate host name check failed"); return -1; }
static void mta_io(struct io *io, int evt) { struct mta_session *s = io->arg; char *line, *msg, *p; size_t len; const char *error; int cont; X509 *x; log_trace(TRACE_IO, "mta: %p: %s %s", s, io_strevent(evt), io_strio(io)); switch (evt) { case IO_CONNECTED: log_info("smtp-out: Connected on session %016"PRIx64, s->id); if (s->use_smtps) { io_set_write(io); mta_start_tls(s); } else { mta_enter_state(s, MTA_BANNER); io_set_read(io); } break; case IO_TLSREADY: log_info("smtp-out: Started TLS on session %016"PRIx64": %s", s->id, ssl_to_text(s->io.ssl)); s->flags |= MTA_TLS; if (mta_verify_certificate(s)) { io_pause(&s->io, IO_PAUSE_IN); break; } case IO_TLSVERIFIED: x = SSL_get_peer_certificate(s->io.ssl); if (x) { log_info("smtp-out: Server certificate verification %s " "on session %016"PRIx64, (s->flags & MTA_VERIFIED) ? "succeeded" : "failed", s->id); X509_free(x); } if (s->use_smtps) { mta_enter_state(s, MTA_BANNER); io_set_read(io); } else mta_enter_state(s, MTA_EHLO); break; case IO_DATAIN: nextline: line = iobuf_getline(&s->iobuf, &len); if (line == NULL) { if (iobuf_len(&s->iobuf) >= LINE_MAX) { mta_error(s, "Input too long"); mta_free(s); return; } iobuf_normalize(&s->iobuf); break; } log_trace(TRACE_MTA, "mta: %p: <<< %s", s, line); if ((error = parse_smtp_response(line, len, &msg, &cont))) { mta_error(s, "Bad response: %s", error); mta_free(s); return; } /* read extensions */ if (s->state == MTA_EHLO) { if (strcmp(msg, "STARTTLS") == 0) s->ext |= MTA_EXT_STARTTLS; else if (strncmp(msg, "AUTH ", 5) == 0) { s->ext |= MTA_EXT_AUTH; if ((p = strstr(msg, " PLAIN")) && (*(p+6) == '\0' || *(p+6) == ' ')) s->ext |= MTA_EXT_AUTH_PLAIN; if ((p = strstr(msg, " LOGIN")) && (*(p+6) == '\0' || *(p+6) == ' ')) s->ext |= MTA_EXT_AUTH_LOGIN; } else if (strcmp(msg, "PIPELINING") == 0) s->ext |= MTA_EXT_PIPELINING; else if (strcmp(msg, "DSN") == 0) s->ext |= MTA_EXT_DSN; } /* continuation reply, we parse out the repeating statuses and ESC */ if (cont) { if (s->replybuf[0] == '\0') (void)strlcat(s->replybuf, line, sizeof s->replybuf); else { line = line + 4; if (isdigit((int)*line) && *(line + 1) == '.' && isdigit((int)*line+2) && *(line + 3) == '.' && isdigit((int)*line+4) && isspace((int)*(line + 5))) (void)strlcat(s->replybuf, line+5, sizeof s->replybuf); else (void)strlcat(s->replybuf, line, sizeof s->replybuf); } goto nextline; } /* last line of a reply, check if we're on a continuation to parse out status and ESC. * if we overflow reply buffer or are not on continuation, log entire last line. */ if (s->replybuf[0] != '\0') { p = line + 4; if (isdigit((int)*p) && *(p + 1) == '.' && isdigit((int)*p+2) && *(p + 3) == '.' && isdigit((int)*p+4) && isspace((int)*(p + 5))) p += 5; if (strlcat(s->replybuf, p, sizeof s->replybuf) >= sizeof s->replybuf) (void)strlcpy(s->replybuf, line, sizeof s->replybuf); } else (void)strlcpy(s->replybuf, line, sizeof s->replybuf); if (s->state == MTA_QUIT) { log_info("smtp-out: Closing session %016"PRIx64 ": %zu message%s sent.", s->id, s->msgcount, (s->msgcount > 1) ? "s" : ""); mta_free(s); return; } io_set_write(io); mta_response(s, s->replybuf); if (s->flags & MTA_FREE) { mta_free(s); return; } if (s->flags & MTA_RECONN) { s->flags &= ~MTA_RECONN; mta_connect(s); return; } iobuf_normalize(&s->iobuf); if (iobuf_len(&s->iobuf)) { log_debug("debug: mta: remaining data in input buffer"); mta_error(s, "Remote host sent too much data"); if (s->flags & MTA_WAIT) s->flags |= MTA_FREE; else mta_free(s); } break; case IO_LOWAT: if (s->state == MTA_BODY) { mta_enter_state(s, MTA_BODY); if (s->flags & MTA_FREE) { mta_free(s); return; } } if (iobuf_queued(&s->iobuf) == 0) io_set_read(io); break; case IO_TIMEOUT: log_debug("debug: mta: %p: connection timeout", s); mta_error(s, "Connection timeout"); if (!s->ready) mta_connect(s); else mta_free(s); break; case IO_ERROR: log_debug("debug: mta: %p: IO error: %s", s, io->error); if (!s->ready) { mta_error(s, "IO Error: %s", io->error); mta_connect(s); break; } else if (!(s->flags & (MTA_FORCE_TLS|MTA_FORCE_ANYSSL))) { /* error in non-strict SSL negotiation, downgrade to plain */ if (s->flags & MTA_TLS) { log_info("smtp-out: Error on session %016"PRIx64 ": opportunistic TLS failed, " "downgrading to plain", s->id); s->flags &= ~MTA_TLS; s->flags |= MTA_DOWNGRADE_PLAIN; mta_connect(s); break; } } mta_error(s, "IO Error: %s", io->error); mta_free(s); break; case IO_TLSERROR: log_debug("debug: mta: %p: TLS IO error: %s", s, io->error); if (!(s->flags & (MTA_FORCE_TLS|MTA_FORCE_ANYSSL))) { /* error in non-strict SSL negotiation, downgrade to plain */ log_info("smtp-out: TLS Error on session %016"PRIx64 ": TLS failed, " "downgrading to plain", s->id); s->flags &= ~MTA_TLS; s->flags |= MTA_DOWNGRADE_PLAIN; mta_connect(s); break; } mta_error(s, "IO Error: %s", io->error); mta_free(s); break; case IO_DISCONNECTED: log_debug("debug: mta: %p: disconnected in state %s", s, mta_strstate(s->state)); mta_error(s, "Connection closed unexpectedly"); if (!s->ready) mta_connect(s); else mta_free(s); break; default: fatalx("mta_io() bad event"); } }
/*! \brief * creates a FILE * from the fd passed by the accept thread. * This operation is potentially expensive (certificate verification), * so we do it in the child thread context. * * \note must decrement ref count before returning NULL on error */ static void *handle_tcptls_connection(void *data) { struct ast_tcptls_session_instance *tcptls_session = data; #ifdef DO_SSL int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept; int ret; char err[256]; #endif /* * open a FILE * as appropriate. */ if (!tcptls_session->parent->tls_cfg) { if ((tcptls_session->f = fdopen(tcptls_session->fd, "w+"))) { if(setvbuf(tcptls_session->f, NULL, _IONBF, 0)) { ast_tcptls_close_session_file(tcptls_session); } } } #ifdef DO_SSL else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) { SSL_set_fd(tcptls_session->ssl, tcptls_session->fd); if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) { ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err)); } else { #if defined(HAVE_FUNOPEN) /* the BSD interface */ tcptls_session->f = funopen(tcptls_session->ssl, ssl_read, ssl_write, NULL, ssl_close); #elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ static const cookie_io_functions_t cookie_funcs = { ssl_read, ssl_write, NULL, ssl_close }; tcptls_session->f = fopencookie(tcptls_session->ssl, "w+", cookie_funcs); #else /* could add other methods here */ ast_debug(2, "no tcptls_session->f methods attempted!\n"); #endif if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { X509 *peer; long res; peer = SSL_get_peer_certificate(tcptls_session->ssl); if (!peer) { ast_log(LOG_ERROR, "No peer SSL certificate to verify\n"); ast_tcptls_close_session_file(tcptls_session); ao2_ref(tcptls_session, -1); return NULL; } res = SSL_get_verify_result(tcptls_session->ssl); if (res != X509_V_OK) { ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); X509_free(peer); ast_tcptls_close_session_file(tcptls_session); ao2_ref(tcptls_session, -1); return NULL; } if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { ASN1_STRING *str; unsigned char *str2; X509_NAME *name = X509_get_subject_name(peer); int pos = -1; int found = 0; for (;;) { /* Walk the certificate to check all available "Common Name" */ /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); if (pos < 0) { break; } str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); ASN1_STRING_to_UTF8(&str2, str); if (str2) { if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) { found = 1; } ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2); OPENSSL_free(str2); } if (found) { break; } } if (!found) { ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); X509_free(peer); ast_tcptls_close_session_file(tcptls_session); ao2_ref(tcptls_session, -1); return NULL; } } X509_free(peer); } } if (!tcptls_session->f) { /* no success opening descriptor stacking */ SSL_free(tcptls_session->ssl); } } #endif /* DO_SSL */ if (!tcptls_session->f) { ast_tcptls_close_session_file(tcptls_session); ast_log(LOG_WARNING, "FILE * open failed!\n"); #ifndef DO_SSL if (tcptls_session->parent->tls_cfg) { ast_log(LOG_WARNING, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); } #endif ao2_ref(tcptls_session, -1); return NULL; } if (tcptls_session->parent->worker_fn) { return tcptls_session->parent->worker_fn(tcptls_session); } else { return tcptls_session; } }
static int mta_verify_certificate(struct mta_session *s) { #define MAX_CERTS 16 #define MAX_CERT_LEN (MAX_IMSGSIZE - (IMSG_HEADER_SIZE + sizeof(req_ca_vrfy))) struct ca_vrfy_req_msg req_ca_vrfy; struct iovec iov[2]; X509 *x; STACK_OF(X509) *xchain; const char *name; unsigned char *cert_der[MAX_CERTS]; int cert_len[MAX_CERTS]; int i, cert_count, res; res = 0; memset(cert_der, 0, sizeof(cert_der)); memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); /* Send the client certificate */ if (s->relay->ca_name) { name = s->relay->ca_name; req_ca_vrfy.fallback = 0; } else { name = s->helo; req_ca_vrfy.fallback = 1; } if (strlcpy(req_ca_vrfy.name, name, sizeof req_ca_vrfy.name) >= sizeof req_ca_vrfy.name) return 0; x = SSL_get_peer_certificate(s->io.ssl); if (x == NULL) return 0; xchain = SSL_get_peer_cert_chain(s->io.ssl); /* * Client provided a certificate and possibly a certificate chain. * SMTP can't verify because it does not have the information that * it needs, instead it will pass the certificate and chain to the * lookup process and wait for a reply. * */ cert_len[0] = i2d_X509(x, &cert_der[0]); X509_free(x); if (cert_len[0] < 0) { log_warnx("warn: failed to encode certificate"); goto end; } log_debug("debug: certificate 0: len=%d", cert_len[0]); if (cert_len[0] > (int)MAX_CERT_LEN) { log_warnx("warn: certificate too long"); goto end; } if (xchain) { cert_count = sk_X509_num(xchain); log_debug("debug: certificate chain len: %d", cert_count); if (cert_count >= MAX_CERTS) { log_warnx("warn: certificate chain too long"); goto end; } } else cert_count = 0; for (i = 0; i < cert_count; ++i) { x = sk_X509_value(xchain, i); cert_len[i+1] = i2d_X509(x, &cert_der[i+1]); if (cert_len[i+1] < 0) { log_warnx("warn: failed to encode certificate"); goto end; } log_debug("debug: certificate %i: len=%d", i+1, cert_len[i+1]); if (cert_len[i+1] > (int)MAX_CERT_LEN) { log_warnx("warn: certificate too long"); goto end; } } tree_xset(&wait_ssl_verify, s->id, s); s->flags |= MTA_WAIT; /* Send the client certificate */ req_ca_vrfy.reqid = s->id; req_ca_vrfy.cert_len = cert_len[0]; req_ca_vrfy.n_chain = cert_count; iov[0].iov_base = &req_ca_vrfy; iov[0].iov_len = sizeof(req_ca_vrfy); iov[1].iov_base = cert_der[0]; iov[1].iov_len = cert_len[0]; m_composev(p_lka, IMSG_MTA_TLS_VERIFY_CERT, 0, 0, -1, iov, nitems(iov)); memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); req_ca_vrfy.reqid = s->id; /* Send the chain, one cert at a time */ for (i = 0; i < cert_count; ++i) { req_ca_vrfy.cert_len = cert_len[i+1]; iov[1].iov_base = cert_der[i+1]; iov[1].iov_len = cert_len[i+1]; m_composev(p_lka, IMSG_MTA_TLS_VERIFY_CHAIN, 0, 0, -1, iov, nitems(iov)); } /* Tell lookup process that it can start verifying, we're done */ memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy); req_ca_vrfy.reqid = s->id; m_compose(p_lka, IMSG_MTA_TLS_VERIFY, 0, 0, -1, &req_ca_vrfy, sizeof req_ca_vrfy); res = 1; end: for (i = 0; i < MAX_CERTS; ++i) free(cert_der[i]); return res; }
Octstr *conn_read_withlen(Connection *conn) { Octstr *result = NULL; unsigned char lengthbuf[4]; long length = 0; /* for compiler please */ int try, retry; lock_in(conn); for (try = 1; try <= 2; try++) { if (try > 1) unlocked_read(conn); do { retry = 0; /* First get the length. */ if (unlocked_inbuf_len(conn) < 4) continue; octstr_get_many_chars(lengthbuf, conn->inbuf, conn->inbufpos, 4); length = decode_network_long(lengthbuf); if (length < 0) { warning(0, "conn_read_withlen: got negative length, skipping"); conn->inbufpos += 4; retry = 1; } } while(retry == 1); /* Then get the data. */ if (unlocked_inbuf_len(conn) - 4 < length) continue; conn->inbufpos += 4; result = unlocked_get(conn, length); gw_claim_area(result); break; } unlock_in(conn); return result; } Octstr *conn_read_packet(Connection *conn, int startmark, int endmark) { int startpos, endpos; Octstr *result = NULL; int try; lock_in(conn); for (try = 1; try <= 2; try++) { if (try > 1) unlocked_read(conn); /* Find startmark, and discard everything up to it */ if (startmark >= 0) { startpos = octstr_search_char(conn->inbuf, startmark, conn->inbufpos); if (startpos < 0) { conn->inbufpos = octstr_len(conn->inbuf); continue; } else { conn->inbufpos = startpos; } } else { startpos = conn->inbufpos; } /* Find first endmark after startmark */ endpos = octstr_search_char(conn->inbuf, endmark, conn->inbufpos); if (endpos < 0) continue; result = unlocked_get(conn, endpos - startpos + 1); gw_claim_area(result); break; } unlock_in(conn); return result; } #ifdef HAVE_LIBSSL X509 *conn_get_peer_certificate(Connection *conn) { /* Don't know if it needed to be locked , but better safe as crash */ lock_out(conn); lock_in(conn); if (conn->peer_certificate == NULL && conn->ssl != NULL) conn->peer_certificate = SSL_get_peer_certificate(conn->ssl); unlock_in(conn); unlock_out(conn); return conn->peer_certificate; } /* * XXX Alex decalred the RSA callback routine static and now we're getting * warning messages for our automatic compilation tests. So we are commenting * the function out to avoid the warnings. * static RSA *tmp_rsa_callback(SSL *ssl, int export, int key_len) { static RSA *rsa = NULL; debug("gwlib.http", 0, "SSL: Generating new RSA key (export=%d, keylen=%d)", export, key_len); if (export) { rsa = RSA_generate_key(key_len, RSA_F4, NULL, NULL); } else { debug("gwlib.http", 0, "SSL: Export not set"); } return rsa; } */ static Mutex **ssl_static_locks = NULL; /* the call-back function for the openssl crypto thread locking */ static void openssl_locking_function(int mode, int n, const char *file, int line) { if (mode & CRYPTO_LOCK) mutex_lock(ssl_static_locks[n-1]); else mutex_unlock(ssl_static_locks[n-1]); } void openssl_init_locks(void) { int c, maxlocks = CRYPTO_num_locks(); gw_assert(ssl_static_locks == NULL); ssl_static_locks = gw_malloc(sizeof(Mutex *) * maxlocks); for (c = 0; c < maxlocks; c++) ssl_static_locks[c] = mutex_create(); /* after the mutexes have been created, apply the call-back to it */ CRYPTO_set_locking_callback(openssl_locking_function); CRYPTO_set_id_callback((CRYPTO_CALLBACK_PTR)gwthread_self); }
/** check if a provided cert matches a passed hostname */ bool _mongoc_ssl_check_cert (SSL *ssl, const char *host, bool weak_cert_validation) { X509 *peer; X509_NAME *subject_name; X509_NAME_ENTRY *entry; ASN1_STRING *entry_data; char *check; int length; int idx; int r = 0; long verify_status; size_t addrlen = 0; struct in_addr addr; int i; int n_sans = -1; int target = GEN_DNS; STACK_OF (GENERAL_NAME) * sans = NULL; BSON_ASSERT (ssl); BSON_ASSERT (host); if (weak_cert_validation) { return true; } /** if the host looks like an IP address, match that, otherwise we assume we * have a DNS name */ if (inet_pton (AF_INET, host, &addr)) { target = GEN_IPADD; addrlen = sizeof (struct in_addr); } peer = SSL_get_peer_certificate (ssl); if (!peer) { return false; } verify_status = SSL_get_verify_result (ssl); /** TODO: should we return this somehow? */ if (verify_status == X509_V_OK) { /* get's a stack of alt names that we can iterate through */ sans = X509_get_ext_d2i ((X509 *)peer, NID_subject_alt_name, NULL, NULL); if (sans) { n_sans = sk_GENERAL_NAME_num (sans); /* loop through the stack, or until we find a match */ for (i = 0; i < n_sans && !r; i++) { const GENERAL_NAME *name = sk_GENERAL_NAME_value (sans, i); /* skip entries that can't apply, I.e. IP entries if we've got a * DNS host */ if (name->type == target) { check = (char *)ASN1_STRING_data (name->d.ia5); length = ASN1_STRING_length (name->d.ia5); switch (target) { case GEN_DNS: /* check that we don't have an embedded null byte */ if ((length == bson_strnlen (check, length)) && _mongoc_ssl_hostcheck (check, host)) { r = 1; } break; case GEN_IPADD: if ((length == addrlen) && !memcmp (check, &addr, length)) { r = 1; } break; default: assert (0); break; } } } GENERAL_NAMES_free (sans); } else { subject_name = X509_get_subject_name (peer); if (subject_name) { idx = -1; i = -1; /* skip to the last common name */ while ((idx = X509_NAME_get_index_by_NID (subject_name, NID_commonName, i)) >= 0) { i = idx; } if (i >= 0) { entry = X509_NAME_get_entry (subject_name, i); entry_data = X509_NAME_ENTRY_get_data (entry); if (entry_data) { /* TODO: I've heard tell that old versions of SSL crap out * when calling ASN1_STRING_to_UTF8 on already utf8 data. * Check up on that */ length = ASN1_STRING_to_UTF8 ((unsigned char **)&check, entry_data); if (length >= 0) { /* check for embedded nulls */ if ((length == bson_strnlen (check, length)) && _mongoc_ssl_hostcheck (check, host)) { r = 1; } OPENSSL_free (check); } } } } } } X509_free (peer); return r; }
void main() { int err; int listen_sock; int sock; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; size_t client_len; char *str; char buffer[4096]; SSL_CTX *ctx; SSL *ssl; SSL_METHOD *meth; X509 *client_cert = NULL; short int s_port = 5555; /* inicializar la librería SSL y registrar los métodos de cifrado soportados */ SSL_library_init(); /* cargar mensajes de error que serán usados */ SSL_load_error_strings(); /* añade soporte para las versión SSL 2 y 3 */ meth = SSLv23_method(); /* crea un nuevo contexto para la utilización de la capa SSL */ ctx = SSL_CTX_new(meth); if (!ctx) { ERR_print_errors_fp(stderr); exit(1); } /* especificar el certificado que utilizará nuestra aplicación */ if (SSL_CTX_use_certificate_file(ctx, RSA_SERVER_CERT, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(1); } /* clave privada de nuestra aplicación */ if (SSL_CTX_use_PrivateKey_file(ctx, RSA_SERVER_KEY, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(1); } /* verifica si la clave esta asociada al certificado */ if (!SSL_CTX_check_private_key(ctx)) { fprintf(stderr,"Hay un problema con el certificado y clave privada del servidor\n"); exit(1); } /* CA utilizado para validar los certificados recibidos por la aplicación */ if (!SSL_CTX_load_verify_locations(ctx, RSA_SERVER_CA_CERT, NULL)) { ERR_print_errors_fp(stderr); exit(1); } /* garantizar que se verifica la autenticidad del otro extremo */ SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); SSL_CTX_set_verify_depth(ctx,1); listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); RETURN_ERR(listen_sock, "socket"); memset (&sa_serv, '\0', sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons (s_port); err = bind(listen_sock, (struct sockaddr*)&sa_serv,sizeof(sa_serv)); RETURN_ERR(err, "bind"); err = listen(listen_sock, 5); RETURN_ERR(err, "listen"); client_len = sizeof(sa_cli); sock = accept(listen_sock, (struct sockaddr*)&sa_cli, &client_len); RETURN_ERR(sock, "accept"); close (listen_sock); char clientIpString[INET_ADDRSTRLEN]; int clientIpInt = sa_cli.sin_addr.s_addr; inet_ntop( AF_INET, &clientIpInt, clientIpString, INET_ADDRSTRLEN ); printf ("Conexion con %s en el puerto %x\n", clientIpString, sa_cli.sin_port); /* crear una estructura SSL */ ssl = SSL_new(ctx); RETURN_NULL(ssl); /* asociar la estructura SSL creada al canal de comunicación */ SSL_set_fd(ssl, sock); /* inicializará el handshake con el servidor */ err = SSL_accept(ssl); RETURN_SSL(err); printf("Cifrado elegido: %s\n", SSL_get_cipher (ssl)); /* Certificado del cliente */ client_cert = SSL_get_peer_certificate(ssl); if (client_cert != NULL) { printf ("Certificado del cliente:\n"); str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0); RETURN_NULL(str); printf ("\t subject: %s\n", str); free (str); str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0); RETURN_NULL(str); printf ("\t issuer: %s\n", str); free (str); X509_free(client_cert); } else printf("El cliente no tiene certificado.\n"); err = SSL_read(ssl, buffer, sizeof(buffer) - 1); RETURN_SSL(err); buffer[err] = '\0'; printf ("Mensaje del cliente: %s\n", buffer); err = SSL_write(ssl, buffer, strlen(buffer)); RETURN_SSL(err); /* cerrar el canal de comunicación */ err = SSL_shutdown(ssl); RETURN_SSL(err); err = close(sock); RETURN_ERR(err, "close"); /* liberar las estructuras creadas de forma dinámica */ SSL_free(ssl); SSL_CTX_free(ctx); }
int main() { //char dest_url[] = "https://www.hp.com"; char dest_url[] = "https://www.baidu.com"; BIO *certbio = NULL; BIO *outbio = NULL; X509 *cert = NULL; X509_NAME *certname = NULL; const SSL_METHOD *method; SSL_CTX *ctx; SSL *ssl; int server = 0; int ret, i; /* ---------------------------------------------------------- * * These function calls initialize openssl for correct work. * * ---------------------------------------------------------- */ OpenSSL_add_all_algorithms(); ERR_load_BIO_strings(); ERR_load_crypto_strings(); SSL_load_error_strings(); /* ---------------------------------------------------------- * * Create the Input/Output BIO's. * * ---------------------------------------------------------- */ certbio = BIO_new(BIO_s_file()); outbio = BIO_new_fp(stdout, BIO_NOCLOSE); /* ---------------------------------------------------------- * * initialize SSL library and register algorithms * * ---------------------------------------------------------- */ if(SSL_library_init() < 0) BIO_printf(outbio, "Could not initialize the OpenSSL library !\n"); /* ---------------------------------------------------------- * * Set SSLv2 client hello, also announce SSLv3 and TLSv1 * * ---------------------------------------------------------- */ method = SSLv23_client_method(); /* ---------------------------------------------------------- * * Try to create a new SSL context * * ---------------------------------------------------------- */ if ( (ctx = SSL_CTX_new(method)) == NULL) BIO_printf(outbio, "Unable to create a new SSL context structure.\n"); /* ---------------------------------------------------------- * * Disabling SSLv2 will leave v3 and TSLv1 for negotiation * * ---------------------------------------------------------- */ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); /* ---------------------------------------------------------- * * Create new SSL connection state object * * ---------------------------------------------------------- */ ssl = SSL_new(ctx); /* ---------------------------------------------------------- * * Make the underlying TCP socket connection * * ---------------------------------------------------------- */ server = create_socket(dest_url, outbio); if(server != 0) BIO_printf(outbio, "Successfully made the TCP connection to: %s.\n", dest_url); /* ---------------------------------------------------------- * * Attach the SSL session to the socket descriptor * * ---------------------------------------------------------- */ SSL_set_fd(ssl, server); /* ---------------------------------------------------------- * * Try to SSL-connect here, returns 1 for success * * ---------------------------------------------------------- */ if ( SSL_connect(ssl) != 1 ) BIO_printf(outbio, "Error: Could not build a SSL session to: %s.\n", dest_url); else BIO_printf(outbio, "Successfully enabled SSL/TLS session to: %s.\n", dest_url); /* ---------------------------------------------------------- * * Get the remote certificate into the X509 structure * * ---------------------------------------------------------- */ cert = SSL_get_peer_certificate(ssl); if (cert == NULL) BIO_printf(outbio, "Error: Could not get a certificate from: %s.\n", dest_url); else BIO_printf(outbio, "Retrieved the server's certificate from: %s.\n", dest_url); /* ---------------------------------------------------------- * * extract various certificate information * * -----------------------------------------------------------*/ certname = X509_NAME_new(); certname = X509_get_subject_name(cert); /* ---------------------------------------------------------- * * display the cert subject here * * -----------------------------------------------------------*/ BIO_printf(outbio, "Displaying the certificate subject data:\n"); X509_NAME_print_ex(outbio, certname, 0, 0); BIO_printf(outbio, "\n"); /* ---------------------------------------------------------- * * Free the structures we don't need anymore * * -----------------------------------------------------------*/ SSL_free(ssl); close(server); X509_free(cert); SSL_CTX_free(ctx); BIO_printf(outbio, "Finished SSL/TLS connection with server: %s.\n", dest_url); return(0); }