示例#1
0
文件: sslclient.c 项目: 274914765/C
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 */
}
示例#2
0
文件: ssl.c 项目: ArdaXi/XChat
/*
    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);
}
示例#3
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, &param);           // 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;
}
示例#4
0
文件: tls_drv.c 项目: adkron/ejabberd
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;
}
示例#5
0
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;

}
示例#6
0
文件: tcp.c 项目: yfqian/libsvc
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;
        }
示例#8
0
/**
 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;
}
示例#9
0
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 */
}
示例#11
0
//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
}
示例#12
0
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
示例#13
0
/*********************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);
}
示例#14
0
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;
}
示例#15
0
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];
    }
}
示例#16
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;
}
示例#17
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;
}
示例#18
0
 /*
  * 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);
}
示例#19
0
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);
}
示例#20
0
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);
}
示例#21
0
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;
}
示例#22
0
/* 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);
}
示例#23
0
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;
}
示例#24
0
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;
	}
}
示例#26
0
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;
}
示例#27
0
文件: conn.c 项目: pwhelan/kannel
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);
}
示例#28
0
/** 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;
}
示例#29
0
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);
}
示例#30
0
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);
}