예제 #1
0
static int
verify_cert_hostname(X509 *cert, char *hostname) {
  int                   extcount, i, j, ok = 0;
  char                  name[256];
  X509_NAME             *subj;
  const char            *extstr;
  CONF_VALUE            *nval;
  const unsigned char   *data;
  X509_EXTENSION        *ext;
  X509V3_EXT_METHOD     *meth;
  STACK_OF(CONF_VALUE)  *val;

  if ((extcount = X509_get_ext_count(cert)) > 0) {
    for (i = 0;  !ok && i < extcount;  i++) {
      ext = X509_get_ext(cert, i);
      extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
      if (!strcasecmp(extstr, "subjectAltName")) {
        if (!(meth = (X509V3_EXT_METHOD *)X509V3_EXT_get(ext))) break;
        data = ext->value->data;

        val = meth->i2v(meth, meth->d2i(0, &data, ext->value->length), 0);
        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)) {
            ok = 1;
            break;
          }
        }
      }
    }
  }

  if (!ok && (subj = X509_get_subject_name(cert)) &&
      X509_NAME_get_text_by_NID(subj, NID_commonName, name, sizeof(name)) > 0) {
    name[sizeof(name) - 1] = '\0';
    if (!strcasecmp(name, hostname)) ok = 1;
  }

  return ok;
}
예제 #2
0
su_inline
int tls_post_connection_check(tport_t *self, tls_t *tls)
{
  X509 *cert;
  int extcount;
  int i, j, error;

  if (!tls) return -1;

  cert = SSL_get_peer_certificate(tls->con);
  if (!cert) {
    SU_DEBUG_7(("%s(%p): Peer did not provide X.509 Certificate.\n", 
				__func__, (void *) self));
    if (self->tp_accepted && tls->verify_incoming)
      return X509_V_ERR_CERT_UNTRUSTED;
    else if (!self->tp_accepted && tls->verify_outgoing)
      return X509_V_ERR_CERT_UNTRUSTED;
    else 
      return X509_V_OK;
  }

  tls->subjects = su_strlst_create(tls->home);
  if (!tls->subjects)
    return X509_V_ERR_OUT_OF_MEM;

  extcount = X509_get_ext_count(cert);

  /* Find matching subjectAltName.DNS */
  for (i = 0; i < extcount; i++) {
    X509_EXTENSION *ext;
    char const *name;
#if OPENSSL_VERSION_NUMBER >  0x10000000L
    const X509V3_EXT_METHOD *vp;
#else
    X509V3_EXT_METHOD *vp;
#endif
    STACK_OF(CONF_VALUE) *values;
    CONF_VALUE *value;
    void *d2i;

    ext = X509_get_ext(cert, i);
    name = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));

    if (strcmp(name, "subjectAltName") != 0)
      continue;

    vp = X509V3_EXT_get(ext); if (!vp) continue;
    d2i = X509V3_EXT_d2i(ext);
    values = vp->i2v(vp, d2i, NULL);

    for (j = 0; j < sk_CONF_VALUE_num(values); j++) {
      value = sk_CONF_VALUE_value(values, j);
      if (strcmp(value->name, "DNS") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
      if (strcmp(value->name, "IP") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
      else if (strcmp(value->name, "URI") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
    }
  }

  {
    X509_NAME *subject;
    char name[256];

    subject = X509_get_subject_name(cert);

    if (subject) {
      if (X509_NAME_get_text_by_NID(subject, NID_commonName,
				    name, sizeof name) > 0) {
	usize_t k, N = su_strlst_len(tls->subjects);
	name[(sizeof name) - 1] = '\0';

	for (k = 0; k < N; k++)
	  if (su_casematch(su_strlst_item(tls->subjects, k), name) == 0)
	    break;

	if (k >= N)
	  su_strlst_dup_append(tls->subjects, name);
      }
    }
  }

  X509_free(cert);

  error = SSL_get_verify_result(tls->con);

  if (cert && error == X509_V_OK)
    tls->x509_verified = 1;

  if (tport_log->log_level >= 7) {
    int i, len = su_strlst_len(tls->subjects);
    for (i=0; i < len; i++)
      SU_DEBUG_7(("%s(%p): Peer Certificate Subject %i: %s\n", \
				  __func__, (void *)self, i, su_strlst_item(tls->subjects, i)));
    if (i == 0)
      SU_DEBUG_7(("%s(%p): Peer Certificate provided no usable subjects.\n",
				  __func__, (void *)self));
  }

  /* Verify incoming connections */
  if (self->tp_accepted) {
    if (!tls->verify_incoming)
      return X509_V_OK;

    if (!tls->x509_verified)
      return error;

    if (tls->verify_subj_in) {
      su_strlst_t const *subjects = self->tp_pri->pri_primary->tp_subjects;
      int i, items;

      items = subjects ? su_strlst_len(subjects) : 0;
      if (items == 0)
        return X509_V_OK;

      for (i=0; i < items; i++) {
	if (tport_subject_search(su_strlst_item(subjects, i), tls->subjects))
	  return X509_V_OK;
      }
      SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (incoming connection)\n", \
				  __func__, (void *)self));

      return X509_V_ERR_CERT_UNTRUSTED;
    }
  }
  /* Verify outgoing connections */
  else {
    char const *subject = self->tp_canon;
    if (!tls->verify_outgoing)
      return X509_V_OK;

    if (!tls->x509_verified || !subject)
      return error;

    if (tls->verify_subj_out) {
      if (tport_subject_search(subject, tls->subjects))
        return X509_V_OK; /* Subject match found in verified certificate chain */
      SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (%s)\n", \
				  __func__, (void *)self, subject));

      return X509_V_ERR_CERT_UNTRUSTED;
    }
  }

  return error;
}
예제 #3
0
파일: tls.c 프로젝트: Zabrane/SPOCP
/*
 * Check that the common name matches the host name
 */
static int
check_cert_chain(conn_t * conn, SSL * ssl, ruleset_t * rs)
{
	X509           *peer;
	X509_NAME      *xn;
	static char     subject[1024];
	int             r = FALSE, extc;

	if (SSL_get_verify_result(ssl) != X509_V_OK) {
		LOG(SPOCP_ERR) traceLog(LOG_ERR,"Certificate doesn't verify");
		return FALSE;
	}

	/*
	 * Check the cert chain. The chain length is automatically checked by
	 * OpenSSL when we set the verify depth in the ctx 
	 */

	peer = SSL_get_peer_certificate(ssl);
	if (!peer) {
		LOG(SPOCP_ERR) traceLog(LOG_ERR,"No peer certificate");
		return TRUE;
	}

	/*
	 * check subjectaltname 
	 */

	if ((extc = X509_get_ext_count(peer)) > 0) {
		int             i;

		for (i = 0; r == FALSE && i < extc; i++) {
			X509_EXTENSION *ext;
			const char     *extstr;

			ext = X509_get_ext(peer, i);
			extstr =
			    OBJ_nid2sn(OBJ_obj2nid
				       (X509_EXTENSION_get_object(ext)));

			if (strcmp(extstr, "subjectAltName") == 0) {
				int             j;
				unsigned char  *data;
				STACK_OF(CONF_VALUE) * val;
				CONF_VALUE     *nval;
				X509V3_EXT_METHOD *meth;

				if ((meth = X509V3_EXT_get(ext)) == 0)
					break;

				data = ext->value->data;

				val =
				    meth->i2v(meth,
					      meth->d2i(NULL, &data,
							ext->value->length),
					      NULL);

				for (j = 0;
				     r == FALSE && i < sk_CONF_VALUE_num(val);
				     j++) {
					nval = sk_CONF_VALUE_value(val, j);
					if (strcasecmp(nval->name, "DNS") == 0
					    && strcasecmp(nval->value,
							  conn->sri.
							  hostname)) {
						r = TRUE;
					}
				}
			}
		}
	}

	if (r == FALSE) {
		/*
		 * Check the subject name 
		 */
		xn = X509_get_subject_name(peer);
		X509_NAME_get_text_by_NID(xn, NID_commonName, subject, 1024);
		subject[1023] = '\0';

		traceLog(LOG_DEBUG,"\"%s\" = \"%s\" ?", subject, conn->sri.hostname);
		if (strcasecmp(subject, conn->sri.hostname) == 0) {
			r = TRUE;
		}
	}

	if (r == TRUE) {
		conn->subjectDN =
		    X509_NAME_oneline(X509_get_subject_name(peer), NULL, 0);
		conn->issuerDN =
		    X509_NAME_oneline(X509_get_issuer_name(peer), NULL, 0);
	}

	X509_free(peer);

	return r;
}
예제 #4
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;
        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, host) ) ||
                (!strcasecmp(nval->name, "iPAddress") &&
                !strcasecmp(nval->value, host)))
            {
              verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print
              ok = 1;
              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;
}
예제 #5
0
long ipfix_ssl_post_connection_check(SSL *ssl, char *host)
{
    X509      *cert;
    X509_NAME *subj;
    char      data[256];
    int       extcount;
    int       ok = 0;

    /* Checking the return from SSL_get_peer_certificate here is not strictly
     * necessary.
     */
    if (!(cert = SSL_get_peer_certificate(ssl)) || !host)
        goto err_occured;
    if ((extcount = X509_get_ext_count(cert)) > 0)
    {
        int i;

        for (i = 0;  i < extcount;  i++)
        {
            char              *extstr;
            X509_EXTENSION    *ext;

            ext = X509_get_ext(cert, i);
            extstr = (char*) OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));

            if (!strcmp(extstr, "subjectAltName"))
            {
                int                  j;
                const unsigned char  *data;
                STACK_OF(CONF_VALUE) *val;
                CONF_VALUE           *nval;
                X509V3_EXT_METHOD    *meth;
                void                 *ext_str = NULL;

                if (!(meth = X509V3_EXT_get(ext)))
                    break;
                data = ext->value->data;

#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
                if (meth->it)
                  ext_str = ASN1_item_d2i(NULL, &data, ext->value->length,
                                          ASN1_ITEM_ptr(meth->it));
                else
                  ext_str = meth->d2i(NULL, &data, ext->value->length);
#else
                ext_str = meth->d2i(NULL, &data, ext->value->length);
#endif
                val = meth->i2v(meth, ext_str, NULL);
                for (j = 0;  j < sk_CONF_VALUE_num(val);  j++)
                {
                    nval = sk_CONF_VALUE_value(val, j);
                    if (!strcmp(nval->name, "DNS") && !strcmp(nval->value, host))
                    {
                        ok = 1;
                        break;
                    }
                }
            }
            if (ok)
                break;
        }
    }

    if (!ok && (subj = X509_get_subject_name(cert)) &&
        X509_NAME_get_text_by_NID(subj, NID_commonName, data, 256) > 0)
    {
        data[255] = 0;
        if (strcasecmp(data, host) != 0)
            goto err_occured;
    }

    X509_free(cert);
    return SSL_get_verify_result(ssl);

err_occured:
    if (cert)
        X509_free(cert);
    return X509_V_ERR_APPLICATION_VERIFICATION;
}
예제 #6
0
int
certproc(int netsock, int filesock)
{
	char		*csr, *chain, *url;
	unsigned char	*csrcp, *chaincp;
	size_t		 csrsz, chainsz;
	int		 i, rc, idx, cc;
	enum certop	 op;
	long		 lval;
	X509		*x, *chainx;
	X509_EXTENSION	*ext;
	X509V3_EXT_METHOD *method;
	void		*entries;
	STACK_OF(CONF_VALUE) *val;
	CONF_VALUE	*nval;

	ext = NULL;
	idx = -1;
	method = NULL;
	chain = csr = url = NULL;
	rc = 0;
	x = chainx = NULL;

	/* File-system and sandbox jailing. */

	if ( ! sandbox_before())
		goto out;

	ERR_load_crypto_strings();

	if ( ! dropfs(PATH_VAR_EMPTY))
		goto out;
	else if ( ! dropprivs())
		goto out;
	else if ( ! sandbox_after())
		goto out;

	/* Read what the netproc wants us to do. */

	op = CERT__MAX;
	if (0 == (lval = readop(netsock, COMM_CSR_OP)))
		op = CERT_STOP;
	else if (CERT_REVOKE == lval || CERT_UPDATE == lval)
		op = lval;

	if (CERT_STOP == op) {
		rc = 1;
		goto out;
	} else if (CERT__MAX == op) {
		warnx("unknown operation from netproc");
		goto out;
	}

	/* 
	 * Pass revocation right through to fileproc. 
	 * If the reader is terminated, ignore it.
	 */

	if (CERT_REVOKE == op) {
		if (writeop(filesock, COMM_CHAIN_OP, FILE_REMOVE) >= 0)
			rc = 1;
		goto out;
	}

	/*
	 * Wait until we receive the DER encoded (signed) certificate
	 * from the network process.
	 * Then convert the DER encoding into an X509 certificate.
	 */

	if (NULL == (csr = readbuf(netsock, COMM_CSR, &csrsz)))
		goto out;

	csrcp = (u_char *)csr;
	x = d2i_X509(NULL, (const u_char **)&csrcp, csrsz);
	if (NULL == x) {
		warnx("d2i_X509");
		goto out;
	}

	/*
	 * Extract the CA Issuers from its NID.
	 * TODO: I have no idea what I'm doing.
	 */

	idx = X509_get_ext_by_NID(x, NID_info_access, idx);
	if (idx >= 0 && NULL != (ext = X509_get_ext(x, idx)))
		method = (X509V3_EXT_METHOD *)X509V3_EXT_get(ext);

	entries = X509_get_ext_d2i(x, NID_info_access, 0, 0);
	if (NULL != method && NULL != entries) {
		val = method->i2v(method, entries, 0);
		for (i = 0; i < sk_CONF_VALUE_num(val); i++) {
			nval = sk_CONF_VALUE_value(val, i);
			if (strcmp(nval->name, "CA Issuers - URI"))
				continue;
			url = strdup(nval->value);
			if (NULL == url) {
				warn("strdup");
				goto out;
			}
			break;
		}
	}

	if (NULL == url) {
		warnx("no CA issuer registered with certificate");
		goto out;
	}

	/* Write the CA issuer to the netsock. */

	if (writestr(netsock, COMM_ISSUER, url) <= 0)
		goto out;

	/* Read the full-chain back from the netsock. */

	if (NULL == (chain = readbuf(netsock, COMM_CHAIN, &chainsz)))
		goto out;

	/*
	 * Then check if the chain is PEM-encoded by looking to see if
	 * it begins with the PEM marker.
	 * If so, ship it as-is; otherwise, convert to a PEM encoded
	 * buffer and ship that.
	 * FIXME: if PEM, re-parse it.
	 */

	if (chainsz <= strlen(MARKER) ||
	    strncmp(chain, MARKER, strlen(MARKER))) {
		chaincp = (u_char *)chain;
		chainx = d2i_X509(NULL, 
			(const u_char **)&chaincp, chainsz);
		if (NULL == chainx) {
			warnx("d2i_X509");
			goto out;
		}
		free(chain);
		if (NULL == (chain = x509buf(chainx, &chainsz)))
			goto out;
	} 

	/* Allow reader termination to just push us out. */

	if (0 == (cc = writeop(filesock, COMM_CHAIN_OP, FILE_CREATE)))
		rc = 1;
	if (cc <= 0)
		goto out;
	if (0 == (cc = writebuf(filesock, COMM_CHAIN, chain, chainsz)))
		rc = 1;
	if (cc <= 0)
		goto out;

	/* 
	 * Next, convert the X509 to a buffer and send that. 
	 * Reader failure doesn't change anything.
	 */

	free(chain);
	if (NULL == (chain = x509buf(x, &chainsz)))
		goto out;
	if (writebuf(filesock, COMM_CSR, chain, chainsz) < 0)
		goto out;

	rc = 1;
out:
	close(netsock);
	close(filesock);
	if (NULL != x)
		X509_free(x);
	if (NULL != chainx)
		X509_free(chainx);
	free(csr);
	free(url);
	free(chain);
	ERR_print_errors_fp(stderr);
	ERR_free_strings();
	return(rc);
}