예제 #1
0
파일: tls.c 프로젝트: hutchinson/freetds
static int
check_alt_names(X509 *cert, const char *hostname)
{
	STACK_OF(GENERAL_NAME) *alt_names;
	int i, num;
	int ret = 1;
	union {
		struct in_addr v4;
		struct in6_addr v6;
	} ip;
	unsigned ip_size = 0;

	/* check whether @hostname is an ip address */
	if (strchr(hostname, ':') != NULL) {
		ip_size = 16;
		ret = inet_pton(AF_INET6, hostname, &ip.v6);
	} else {
		ip_size = 4;
		ret = inet_pton(AF_INET, hostname, &ip.v4);
	}
	if (ret == 0)
		return -1;

	ret = -1;

	alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
	if (!alt_names)
		return ret;

	num = sk_GENERAL_NAME_num(alt_names);
	tdsdump_log(TDS_DBG_INFO1, "Alt names number %d\n", num);
	for (i = 0; i < num; ++i) {
		const char *altptr;
		size_t altlen;

		const GENERAL_NAME *name = sk_GENERAL_NAME_value(alt_names, i);
		if (!name)
			continue;

		altptr = (const char *) ASN1_STRING_data(name->d.ia5);
		altlen = (size_t) ASN1_STRING_length(name->d.ia5);

		if (name->type == GEN_DNS && ip_size == 0) {
			ret = 0;
			if (!check_name_match(name->d.dNSName, hostname))
				continue;
		} else if (name->type == GEN_IPADD && ip_size != 0) {
			ret = 0;
			if (altlen != ip_size || memcmp(altptr, &ip, altlen) != 0)
				continue;
		} else {
			continue;
		}

		sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
		return 1;
	}
	sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
	return ret;
}
예제 #2
0
파일: imap-send.c 프로젝트: Fykec/git
static int verify_hostname(X509 *cert, const char *hostname)
{
	int len;
	X509_NAME *subj;
	char cname[1000];
	int i, found;
	STACK_OF(GENERAL_NAME) *subj_alt_names;

	/* try the DNS subjectAltNames */
	found = 0;
	if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) {
		int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names);
		for (i = 0; !found && i < num_subj_alt_names; i++) {
			GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
			if (subj_alt_name->type == GEN_DNS &&
			    strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length &&
			    host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data)))
				found = 1;
		}
		sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
	}
	if (found)
		return 0;

	/* try the common name */
	if (!(subj = X509_get_subject_name(cert)))
		return error("cannot get certificate subject");
	if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0)
		return error("cannot get certificate common name");
	if (strlen(cname) == (size_t)len && host_matches(hostname, cname))
		return 0;
	return error("certificate owner '%s' does not match hostname '%s'",
		     cname, hostname);
}
예제 #3
0
/* Gets information about the peer's X509 cert as a tsi_peer object. */
static tsi_result peer_from_x509(X509* cert, int include_certificate_type,
                                 tsi_peer* peer) {
  /* TODO(jboeuf): Maybe add more properties. */
  GENERAL_NAMES* subject_alt_names =
      X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
  int subject_alt_name_count =
      (subject_alt_names != NULL) ? sk_GENERAL_NAME_num(subject_alt_names) : 0;
  size_t property_count = (include_certificate_type ? 1 : 0) +
                          1 /* common name */ + subject_alt_name_count;
  tsi_result result = tsi_construct_peer(property_count, peer);
  if (result != TSI_OK) return result;
  do {
    if (include_certificate_type) {
      result = tsi_construct_string_peer_property_from_cstring(
          TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
          &peer->properties[0]);
      if (result != TSI_OK) break;
    }
    result = peer_property_from_x509_common_name(
        cert, &peer->properties[include_certificate_type ? 1 : 0]);
    if (result != TSI_OK) break;

    if (subject_alt_name_count != 0) {
      result = add_subject_alt_names_properties_to_peer(peer, subject_alt_names,
                                                        subject_alt_name_count);
      if (result != TSI_OK) break;
    }
  } while (0);

  if (subject_alt_names != NULL) {
    sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
  }
  if (result != TSI_OK) tsi_peer_destruct(peer);
  return result;
}
예제 #4
0
/**
* Tries to find a match for hostname in the certificate's Subject Alternative Name extension.
*
* Returns MatchFound if a match was found.
* Returns MatchNotFound if no matches were found.
* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
* Returns NoSANPresent if the SAN extension was not present in the certificate.
*/
static HostnameValidationResult matches_subject_alternative_name(const char *hostname, const X509 *server_cert) {
	HostnameValidationResult result = MatchNotFound;
	int i;
	int san_names_nb = -1;
	STACK_OF(GENERAL_NAME) *san_names = NULL;

	// Try to extract the names within the SAN extension from the certificate
	san_names = X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name, NULL, NULL);
	if (san_names == NULL) {
		return NoSANPresent;
	}
	san_names_nb = sk_GENERAL_NAME_num(san_names);

	// Check each name within the extension
	for (i=0; i<san_names_nb; i++) {
		const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);

		if (current_name->type == GEN_DNS) {
			// Current name is a DNS name, let's check it
			result = validate_name(hostname, current_name->d.dNSName);
			if (result != MatchNotFound) {
				break;
			}
		}
	}
	sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);

	return result;
}
예제 #5
0
/* Make sure we do the right thing. Add here if you convert ones in tree */
int
main(int argc, char **argv)
{
	ASN1_INTEGER_free(NULL);
	ASN1_OBJECT_free(NULL);
	ASN1_OCTET_STRING_free(NULL);

	BIO_free_all(NULL);

	DIST_POINT_free(NULL);

	EVP_PKEY_free(NULL);

	GENERAL_NAME_free(NULL);
	GENERAL_SUBTREE_free(NULL);

	NAME_CONSTRAINTS_free(NULL);

	sk_GENERAL_NAME_pop_free(NULL, GENERAL_NAME_free);
	sk_X509_NAME_ENTRY_pop_free(NULL, X509_NAME_ENTRY_free);

	X509_NAME_ENTRY_free(NULL);

	printf("PASS\n");

	return (0);
}
예제 #6
0
/* based on verify_extract_name from tls_client.c in postfix */
static gboolean irssi_ssl_verify_hostname(X509 *cert, const char *hostname)
{
	int gen_index, gen_count;
	gboolean matched = FALSE, has_dns_name = FALSE;
	const char *cert_dns_name;
	char *cert_subject_cn;
	const GENERAL_NAME *gn;
	STACK_OF(GENERAL_NAME) * gens;
	GString *alt_names;

	alt_names = g_string_new("");

	/* Verify the dNSName(s) in the peer certificate against the hostname. */
	gens = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
	if (gens) {
		gen_count = sk_GENERAL_NAME_num(gens);
		for (gen_index = 0; gen_index < gen_count && !matched; ++gen_index) {
			gn = sk_GENERAL_NAME_value(gens, gen_index);
			if (gn->type != GEN_DNS)
				continue;

			/* Even if we have an invalid DNS name, we still ultimately
			   ignore the CommonName, because subjectAltName:DNS is
			   present (though malformed). */
			has_dns_name = TRUE;
			cert_dns_name = tls_dns_name(gn);
			if (cert_dns_name && *cert_dns_name) {
				g_string_append_printf(alt_names, " '%s'", cert_dns_name);
				matched = match_hostname(cert_dns_name, hostname);
			}
    	}

	    /* Free stack *and* member GENERAL_NAME objects */
	    sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
	}

	if (has_dns_name) {
		if (! matched) {
			/* The CommonName in the issuer DN is obsolete when SubjectAltName is available. */
			g_warning("None of the Subject Alt Names%s in the certificate match hostname '%s'", alt_names->str, hostname);
		}
		g_string_free(alt_names, TRUE);
		return matched;
	} else { /* No subjectAltNames, look at CommonName */
		g_string_free(alt_names, TRUE);
		cert_subject_cn = tls_text_name(X509_get_subject_name(cert), NID_commonName);
	    if (cert_subject_cn && *cert_subject_cn) {
	    	matched = match_hostname(cert_subject_cn, hostname);
	    	if (! matched) {
				g_warning("SSL certificate common name '%s' doesn't match host name '%s'", cert_subject_cn, hostname);
	    	}
	    } else {
	    	g_warning("No subjectAltNames and no valid common name in certificate");
	    }
	    free(cert_subject_cn);
	}

	return matched;
}
예제 #7
0
void AC_ATT_HOLDER_free(AC_ATT_HOLDER *a)
{
  if (a == NULL) return;

  sk_GENERAL_NAME_pop_free(a->grantor, GENERAL_NAME_free);
  sk_AC_ATTRIBUTE_pop_free(a->attributes, AC_ATTRIBUTE_free);
  OPENSSL_free(a);
}
예제 #8
0
int
eventer_ssl_get_san_values(eventer_ssl_ctx_t *ctx,
                        X509_STORE_CTX *x509ctx) {
  STACK_OF(GENERAL_NAME) * altnames;
  X509 *peer;
  int pos = 0;

  if(!x509ctx) return 0;
  peer = X509_STORE_CTX_get_current_cert(x509ctx);
  altnames = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL);
  if (altnames) {
    int i;
    int numalts = sk_GENERAL_NAME_num(altnames);
    char cn[4096];
    mtev_boolean written = mtev_false;

    memset(cn, 0, 4096);
    for (i = 0; i < numalts; i++) {
      const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
      if (check->type != GEN_DNS) {
        continue;
      }
      ASN1_STRING *data = check->d.dNSName;
      if (written) {
        /* Leave space for comma, space, data, and null byte */
        if (data->length + pos > (int)sizeof(cn) - 3) {
          continue;
        }
        cn[pos] = ',';
        cn[pos+1] = ' ';
        pos+=2;
      }
      else {
        /* Leave space for data and null byte */
        if (data->length + pos > (int)sizeof(cn) - 1) {
          continue;
        }
        written = mtev_true;
      }
      memcpy(cn+pos, data->data, data->length);
      cn[data->length+pos] = '\0';
      pos = strlen(cn);
    }
    if (pos > 0) {
      if (ctx->san_list != NULL) {
        free(ctx->san_list);
      }
      ctx->san_list = strdup(cn);
    }
    sk_GENERAL_NAME_pop_free(altnames, GENERAL_NAME_free);
  }
  return 1;
}
예제 #9
0
/* return an array of (RFC 6125 coined) DNS-IDs and CN-IDs in a certificate */
BOOL SSL_X509_getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids)
{
    STACK_OF(GENERAL_NAME) *names;
    BIO *bio;
    X509_NAME *subj;
    char **cpp;
    int i, n;

    if (!x509 || !(*ids = apr_array_make(p, 0, sizeof(char *)))) {
        *ids = NULL;
        return FALSE;
    }

    /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */
    if ((names = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL)) &&
        (bio = BIO_new(BIO_s_mem()))) {
        GENERAL_NAME *name;

        for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
            name = sk_GENERAL_NAME_value(names, i);
            if (name->type == GEN_DNS) {
                ASN1_STRING_print_ex(bio, name->d.ia5, ASN1_STRFLGS_ESC_CTRL|
                                     ASN1_STRFLGS_UTF8_CONVERT);
                n = BIO_pending(bio);
                if (n > 0) {
                    cpp = (char **)apr_array_push(*ids);
                    *cpp = apr_palloc(p, n+1);
                    n = BIO_read(bio, *cpp, n);
                    (*cpp)[n] = NUL;
                }
            }
        }
        BIO_free(bio);
    }

    if (names)
        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);

    /* Second, the CN-IDs (commonName attributes in the subject DN) */
    subj = X509_get_subject_name(x509);
    i = -1;
    while ((i = X509_NAME_get_index_by_NID(subj, NID_commonName, i)) != -1) {
        cpp = (char **)apr_array_push(*ids);
        *cpp = SSL_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i));
    }

    return apr_is_empty_array(*ids) ? FALSE : TRUE;
}
예제 #10
0
/* See RFC 5280 section 4.2.1.6 for SubjectAltName details. */
static int
tls_cert_get_altnames(struct tls *ctx, struct tls_cert *cert, X509 *x509_cert)
{
	STACK_OF(GENERAL_NAME) *altname_stack = NULL;
	GENERAL_NAME *altname;
	int count, i;
	int rv = -1;

	altname_stack = X509_get_ext_d2i(x509_cert, NID_subject_alt_name, NULL, NULL);
	if (altname_stack == NULL)
		return 0;

	count = sk_GENERAL_NAME_num(altname_stack);
	if (count == 0) {
		rv = 0;
		goto out;
	}

	cert->subject_alt_names = calloc(sizeof (struct tls_cert_general_name), count);
	if (cert->subject_alt_names == NULL) {
		tls_set_error(ctx, "calloc");
		goto out;
	}

	for (i = 0; i < count; i++) {
		altname = sk_GENERAL_NAME_value(altname_stack, i);

		if (altname->type == GEN_DNS) {
			rv = tls_load_alt_ia5string(ctx, altname->d.dNSName, cert, TLS_CERT_GNAME_DNS, 1, UB_GNAME_DNS, "dns");
		} else if (altname->type == GEN_EMAIL) {
			rv = tls_load_alt_ia5string(ctx, altname->d.rfc822Name, cert, TLS_CERT_GNAME_EMAIL, 1, UB_GNAME_EMAIL, "email");
		} else if (altname->type == GEN_URI) {
			rv = tls_load_alt_ia5string(ctx, altname->d.uniformResourceIdentifier, cert, TLS_CERT_GNAME_URI, 1, UB_GNAME_URI, "uri");
		} else if (altname->type == GEN_IPADD) {
			rv = tls_load_alt_ipaddr(ctx, altname->d.iPAddress, cert);
		} else {
			/* ignore unknown types */
			rv = 0;
		}
		if (rv < 0)
			goto out;
	}
	rv = 0;
out:
	sk_GENERAL_NAME_pop_free(altname_stack, GENERAL_NAME_free);
	return rv;
}
예제 #11
0
int get_subjectaltname(X509* cert, char* buf, int buf_len){

/*
    Copy "," separated dNSName values
    of the subjectAltName extension, to pBuf
*/

  GENERAL_NAMES *gens;
  GENERAL_NAME  *gen;
  int i;
  char *sub_str= buf;
  int space_taken=0;
  int space_left= buf_len;

  gens = X509_get_ext_d2i(cert , NID_subject_alt_name, NULL, NULL);

  for(i = 0; i < sk_GENERAL_NAME_num(gens); i++){
      gen = sk_GENERAL_NAME_value(gens, i);
      syslog(LOG_INFO,"1sub_str");

      if((gen->type == GEN_DNS)||(gen->type == GEN_URI)){
          if(0 < space_left)
	  space_taken= copy_csv_to_buffer(sub_str, (char*)gen->d.ia5->data, buf_len, space_left);
	  space_left= space_left -space_taken;
      }

      if(gen->type == GEN_IPADD) {
          if(0 < space_left) {
              const int oline_len = 40;
	      char oline[oline_len];
	      oline[0]='\0';
	      ip_to_string(oline, oline_len, gen);
	      space_taken= copy_csv_to_buffer(sub_str,  oline, buf_len, space_left);
	      space_left= space_left - space_taken;
	  }
      }

      syslog(LOG_INFO,"2 sub_str: %s space_taken:%d space_left:%d",sub_str, space_taken, space_left);
  }

  sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
  return CERT_OK;

}
/**
 * Tries to find a match for hostname in the certificate's Subject Alternative Name extension.
 *
 * Returns MatchFound if a match was found.
 * Returns MatchNotFound if no matches were found.
 * Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
 * Returns NoSANPresent if the SAN extension was not present in the certificate.
 */
static HostnameValidationResult matches_subject_alternative_name(
		const char *hostname, const X509 *server_cert) {
	HostnameValidationResult result = MatchNotFound;
	int i;
	int san_names_nb = -1;
	STACK_OF(GENERAL_NAME) *san_names = NULL;

	// Try to extract the names within the SAN extension from the certificate
	san_names = X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name,
			NULL, NULL);
	if (san_names == NULL) {
		return NoSANPresent;
	}

	san_names_nb = sk_GENERAL_NAME_num(san_names);
	// Check each name within the extension
	for (i = 0; i < san_names_nb; i++) {
		const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);

		if (current_name->type == GEN_DNS) {
			// Current name is a DNS name, let's check it
			char *dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName);

			// Make sure there isn't an embedded NUL character in the DNS name
			if (ASN1_STRING_length(current_name->d.dNSName)
					!= strlen(dns_name)) {
				result = MalformedCertificate;
				break;
			} else { // Compare expected hostname with the DNS name
				if (hostmatch(hostname, dns_name) == CURL_HOST_MATCH) {
					result = MatchFound;
					break;
				}
			}
		}
	}
	sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);

	return result;
}
/**
* Tries to find a match for hostname in the certificate's Subject Alternative
* Name extension.
*
* Returns AMQP_HVR_MATCH_FOUND if a match was found.
* Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
* Returns AMQP_HVR_MALFORMED_CERTIFICATE if any of the hostnames had a NUL
* character embedded in it.
* Returns AMQP_HVR_NO_SAN_PRESENT if the SAN extension was not present in the
* certificate.
*/
static amqp_hostname_validation_result amqp_matches_subject_alternative_name(
    const char *hostname, const X509 *server_cert) {
  amqp_hostname_validation_result result = AMQP_HVR_MATCH_NOT_FOUND;
  int i;
  int san_names_nb = -1;
  STACK_OF(GENERAL_NAME) *san_names = NULL;

  // Try to extract the names within the SAN extension from the certificate
  san_names =
      X509_get_ext_d2i((X509 *)server_cert, NID_subject_alt_name, NULL, NULL);
  if (san_names == NULL) {
    return AMQP_HVR_NO_SAN_PRESENT;
  }
  san_names_nb = sk_GENERAL_NAME_num(san_names);

  // Check each name within the extension
  for (i = 0; i < san_names_nb; i++) {
    const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);

    if (current_name->type == GEN_DNS) {
      // Current name is a DNS name, let's check it
      char *dns_name = (char *)ASN1_STRING_data(current_name->d.dNSName);

      // Make sure there isn't an embedded NUL character in the DNS name
      if ((size_t)ASN1_STRING_length(current_name->d.dNSName) !=
          strlen(dns_name)) {
        result = AMQP_HVR_MALFORMED_CERTIFICATE;
        break;
      } else {  // Compare expected hostname with the DNS name
        if (amqp_hostcheck(dns_name, hostname) == AMQP_HCR_MATCH) {
          result = AMQP_HVR_MATCH_FOUND;
          break;
        }
      }
    }
  }
  sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);

  return result;
}
int openssl_cert_match_name(SSL *ssl, const char *verify_name)
{
	X509 *cert;
	STACK_OF(GENERAL_NAME) *gnames;
	const GENERAL_NAME *gn;
	const char *dnsname;
	bool dns_names = FALSE;
	unsigned int i, count;
	int ret;

	cert = SSL_get_peer_certificate(ssl);
	i_assert(cert != NULL);

	/* verify against SubjectAltNames */
	gnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
	count = gnames == NULL ? 0 : sk_GENERAL_NAME_num(gnames);
	for (i = 0; i < count; i++) {
		gn = sk_GENERAL_NAME_value(gnames, i);
		if (gn->type == GEN_DNS) {
			dns_names = TRUE;
			dnsname = get_general_dns_name(gn);
			if (openssl_hostname_equals(dnsname, verify_name))
				break;
		}
	}
	sk_GENERAL_NAME_pop_free(gnames, GENERAL_NAME_free);

	/* verify against CommonName only when there wasn't any DNS
	   SubjectAltNames */
	if (dns_names)
		ret = i < count ? 0 : -1;
	else if (openssl_hostname_equals(get_cname(cert), verify_name))
		ret = 0;
	else
		ret = -1;
	X509_free(cert);
	return ret;
}
예제 #15
0
/* See RFC 5280 section 4.2.1.6 for SubjectAltName details. */
static gboolean
rspamd_tls_check_subject_altname (X509 *cert, const char *name)
{
	STACK_OF(GENERAL_NAME) *altname_stack = NULL;
	int addrlen, type;
	int count, i;
	union {
		struct in_addr ip4;
		struct in6_addr ip6;
	} addrbuf;
	gboolean ret = FALSE;

	altname_stack = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL);

	if (altname_stack == NULL) {
		return FALSE;
	}

	if (inet_pton (AF_INET, name, &addrbuf) == 1) {
		type = GEN_IPADD;
		addrlen = 4;
	}
	else if (inet_pton (AF_INET6, name, &addrbuf) == 1) {
		type = GEN_IPADD;
		addrlen = 16;
	}
	else {
		type = GEN_DNS;
		addrlen = 0;
	}

	count = sk_GENERAL_NAME_num (altname_stack);

	for (i = 0; i < count; i++) {
		GENERAL_NAME *altname;

		altname = sk_GENERAL_NAME_value (altname_stack, i);

		if (altname->type != type) {
			continue;
		}

		if (type == GEN_DNS) {
			unsigned char *data;
			int format, len;

			format = ASN1_STRING_type (altname->d.dNSName);

			if (format == V_ASN1_IA5STRING) {
				data = ASN1_STRING_data (altname->d.dNSName);
				len = ASN1_STRING_length (altname->d.dNSName);

				if (len < 0 || len != (gint)strlen (data)) {
					ret = FALSE;
					break;
				}

				/*
				 * Per RFC 5280 section 4.2.1.6:
				 * " " is a legal domain name, but that
				 * dNSName must be rejected.
				 */
				if (strcmp (data, " ") == 0) {
					ret = FALSE;
					break;
				}

				if (rspamd_tls_match_name (data, name)) {
					ret = TRUE;
					break;
				}
			}
		}
		else if (type == GEN_IPADD) {
			unsigned char *data;
			int datalen;

			datalen = ASN1_STRING_length (altname->d.iPAddress);
			data = ASN1_STRING_data (altname->d.iPAddress);

			if (datalen < 0) {
				ret = FALSE;
				break;
			}

			/*
			 * Per RFC 5280 section 4.2.1.6:
			 * IPv4 must use 4 octets and IPv6 must use 16 octets.
			 */
			if (datalen == addrlen && memcmp (data, &addrbuf, addrlen) == 0) {
				ret = TRUE;
				break;
			}
		}
	}

	sk_GENERAL_NAME_pop_free (altname_stack, GENERAL_NAME_free);
	return ret;
}
예제 #16
0
파일: turbo_ffi_wrap.c 프로젝트: kidd/turbo
static int32_t matches_subject_alternative_name(
    const char *hostname,
    const X509 *server_cert)
{
    int32_t result = MatchNotFound;
    int32_t i;
    int32_t san_names_nb = -1;
    int32_t hostname_is_domain;
    const char *subdomain_offset;
    size_t dns_name_sz;
    size_t hostname_sz = strlen(hostname);
    STACK_OF(GENERAL_NAME) *san_names = 0;

    san_names = X509_get_ext_d2i(
                    (X509 *) server_cert,
                    NID_subject_alt_name,
                    0,
                    0);
    if (san_names == 0)
        return NoSANPresent;
    san_names_nb = sk_GENERAL_NAME_num(san_names);
    for (i=0; i<san_names_nb; i++) {
        const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);
        if (current_name->type == GEN_DNS) {
            char *dns_name = (char *)ASN1_STRING_data(current_name->d.dNSName);
            dns_name_sz = strlen(dns_name);
            if (ASN1_STRING_length(current_name->d.dNSName) != dns_name_sz) {
                result = MalformedCertificate;
                break;
            } else {
                if (strcasecmp(hostname, dns_name) == 0) {
                    result = MatchFound;
                    break;
                }
                if (dns_name_sz <= 2)
                    continue;
                if (dns_name[0] == '*' && dns_name[1] == '.') {
                    // Wildcard subdomain.
                    subdomain_offset = strchr(hostname, '.');
                    if (!subdomain_offset)
                        continue;
                    hostname_is_domain = strchr(subdomain_offset, '.') ? 0 : 1;
                    if (hostname_is_domain) {
                        if (strcasecmp(hostname, dns_name + 2) == 0) {
                            result = MatchFound;
                            break;
                        }
                    } else {
                        if (hostname_sz - (subdomain_offset - hostname) > 0) {
                            if (strcasecmp(
                                        subdomain_offset + 1,
                                        dns_name + 2) == 0) {
                                result = MatchFound;
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
    sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);

    return result;
}
예제 #17
0
파일: tls_client.c 프로젝트: 1514louluo/acl
static void verify_extract_name(TLS_SESS_STATE *TLScontext, X509 *peercert,
	const TLS_CLIENT_START_PROPS *props)
{
    int     i;
    int     r;
    int     matched = 0;
    const char *dnsname;
    const GENERAL_NAME *gn;

    STACK_OF(GENERAL_NAME) * gens;

    /*
     * On exit both peer_CN and issuer_CN should be set.
     */
    TLScontext->issuer_CN = tls_issuer_CN(peercert, TLScontext);

    /*
     * Is the certificate trust chain valid and trusted?
     */
    if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
	TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED;

    if (TLS_CERT_IS_TRUSTED(TLScontext) && props->tls_level >= TLS_LEV_VERIFY) {

	/*
	 * Verify the dNSName(s) in the peer certificate against the nexthop
	 * and hostname.
	 * 
	 * If DNS names are present, we use the first matching (or else simply
	 * the first) DNS name as the subject CN. The CommonName in the
	 * issuer DN is obsolete when SubjectAltName is available. This
	 * yields much less surprising logs, because we log the name we
	 * verified or a name we checked and failed to match.
	 * 
	 * XXX: The nexthop and host name may both be the same network address
	 * rather than a DNS name. In this case we really should be looking
	 * for GEN_IPADD entries, not GEN_DNS entries.
	 * 
	 * XXX: In ideal world the caller who used the address to build the
	 * connection would tell us that the nexthop is the connection
	 * address, but if that is not practical, we can parse the nexthop
	 * again here.
	 */
	gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
	if (gens) {
	    r = sk_GENERAL_NAME_num(gens);
	    for (i = 0; i < r && !matched; ++i) {
		gn = sk_GENERAL_NAME_value(gens, i);
		if (gn->type != GEN_DNS)
		    continue;

		/*
		 * Even if we have an invalid DNS name, we still ultimately
		 * ignore the CommonName, because subjectAltName:DNS is
		 * present (though malformed). Replace any previous peer_CN
		 * if empty or we get a match.
		 * 
		 * We always set at least an empty peer_CN if the ALTNAME cert
		 * flag is set. If not, we set peer_CN from the cert
		 * CommonName below, so peer_CN is always non-null on return.
		 */
		TLScontext->peer_status |= TLS_CERT_FLAG_ALTNAME;
		dnsname = tls_dns_name(gn, TLScontext);
		if (dnsname && *dnsname) {
		    matched = match_hostname(dnsname, props);
		    if (TLScontext->peer_CN
			    && (matched || *TLScontext->peer_CN == 0)) {
			acl_myfree(TLScontext->peer_CN);
			TLScontext->peer_CN = 0;
		    }
		}
		if (TLScontext->peer_CN == 0)
		    TLScontext->peer_CN = acl_mystrdup(dnsname ? dnsname : "");
	    }

	    /*
	     * (Sam Rushing, Ironport) Free stack *and* member GENERAL_NAME
	     * objects
	     */
	    sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
	}

	/*
	 * No subjectAltNames, peer_CN is taken from CommonName.
	 */
	if (TLScontext->peer_CN == 0) {
	    TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);
	    if (*TLScontext->peer_CN)
		matched = match_hostname(TLScontext->peer_CN, props);
	}
	if (matched)
	    TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED;

	/*
	 * - Matched: Trusted and peername matches - Trusted: Signed by
	 * trusted CA(s), but peername not matched - Untrusted: Can't verify
	 * the trust chain, reason already logged.
	 */
	if (TLScontext->log_level >= 2)
	    acl_msg_info("%s: %s subject_CN=%s, issuer_CN=%s", props->namaddr,
		    TLS_CERT_IS_MATCHED(TLScontext) ? "Matched" :
		    TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
		    TLScontext->peer_CN, TLScontext->issuer_CN);
    } else
	TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);

    /*
     * Give them a clue. Problems with trust chain verification were logged
     * when the session was first negotiated, before the session was stored
     * into the cache. We don't want mystery failures, so log the fact the
     * real problem is to be found in the past.
     */
    if (TLScontext->session_reused
	    && !TLS_CERT_IS_TRUSTED(TLScontext)
	    && TLScontext->log_level >= 1)
	acl_msg_info("%s: re-using session with untrusted certificate, "
		"look for details earlier in the log", props->namaddr);
}
예제 #18
0
파일: OsSSL.cpp 프로젝트: LordGaav/sipxecs
void OsSSL::logConnectParams(const OsSysLogFacility facility, ///< callers facility
                             const OsSysLogPriority priority, ///< log priority
                             const char* callerMsg,  ///< Identifies circumstances of connection
                             SSL*  connection  ///< SSL connection to be described
                             )
{
   if (connection)
   {
      char* subjectStr = NULL;
      char* issuerStr = NULL;

      UtlString altNames;

      // Extract the subject and issuer information about the peer
      // and the certificate validation result.  Neither of these
      // are meaningful without the other.
      //    (note various dynamically allocated items - freed below)
      int   validity  = SSL_get_verify_result(connection);
      X509* peer_cert = SSL_get_peer_certificate(connection);
      if (peer_cert)
      {
         subjectStr = X509_NAME_oneline(X509_get_subject_name(peer_cert),0,0);
         issuerStr = X509_NAME_oneline(X509_get_issuer_name(peer_cert),0,0);

         // Look for the subjectAltName URI or DNS attributes
         GENERAL_NAMES* names;
         names = (GENERAL_NAMES*)X509_get_ext_d2i(peer_cert, NID_subject_alt_name, NULL, NULL);
         for(int i = 0; i < sk_GENERAL_NAME_num(names); i++)
         {
            GENERAL_NAME* name = sk_GENERAL_NAME_value(names, i);

            switch (name->type)
            {
            case GEN_DNS:
            {
               ASN1_IA5STRING* uri = name->d.uniformResourceIdentifier;
               if (!altNames.isNull())
               {
                  altNames.append(",");
               }
               altNames.append((const char*)(uri->data),uri->length);
            }
            break;

            case GEN_URI:
            {
               ASN1_IA5STRING* uri = name->d.uniformResourceIdentifier;
               if (!altNames.isNull())
               {
                  altNames.append(",");
               }
               altNames.append((const char*)(uri->data),uri->length);
            }
            break;

            default:
               // don't care about any other values
               break;
            }
         }
         sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
      }

      // Get the name of the encryption applied to the connection
      const char* cipher = SSL_get_cipher(connection);

      OsSysLog::add(FAC_KERNEL, PRI_DEBUG,
                    "%s SSL Connection:\n"
                    "   status:  %s\n"
                    "   peer:    '%s'\n"
                    "   alt names: %s\n"
                    "   cipher:  '%s'\n"
                    "   issuer:  '%s'",
                    callerMsg,
                    validity == X509_V_OK ? "Verified" : "NOT VERIFIED",
                    subjectStr ? subjectStr : "",
                    altNames.isNull() ? "" : altNames.data(),
                    cipher     ? cipher     : "",
                    issuerStr  ? issuerStr  : ""
                    );

      // Release the various dynamic things
      if (subjectStr)
      {
         OPENSSL_free(subjectStr);
      }
      if (issuerStr)
      {
         OPENSSL_free(issuerStr);
      }
      if (peer_cert)
      {
         X509_free(peer_cert);
      }
   }
   else
   {
      OsSysLog::add(FAC_KERNEL, PRI_ERR,
                    "OsSSL::logConnectParams called by %s with NULL connection",
                    callerMsg
                    );
   }
}
예제 #19
0
static void verify_extract_name(TLS_SESS_STATE *TLScontext, X509 *peercert,
				        const TLS_CLIENT_START_PROPS *props)
{
    int     i;
    int     r;
    int     matched = 0;
    int     dnsname_match;
    int     verify_peername = 0;
    int     log_certmatch;
    int     verbose;
    const char *dnsname;
    const GENERAL_NAME *gn;
    general_name_stack_t *gens;

    /*
     * On exit both peer_CN and issuer_CN should be set.
     */
    TLScontext->issuer_CN = tls_issuer_CN(peercert, TLScontext);

    /*
     * Is the certificate trust chain valid and trusted?
     */
    if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
	TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED;

    /*
     * With fingerprint or dane we may already be done. Otherwise, verify the
     * peername if using traditional PKI or DANE with trust-anchors.
     */
    if (!TLS_CERT_IS_MATCHED(TLScontext)
	&& TLS_CERT_IS_TRUSTED(TLScontext)
	&& TLS_MUST_TRUST(props->tls_level))
	verify_peername = 1;

    /* Force cert processing so we can log the data? */
    log_certmatch = TLScontext->log_mask & TLS_LOG_CERTMATCH;

    /* Log cert details when processing? */
    verbose = log_certmatch || (TLScontext->log_mask & TLS_LOG_VERBOSE);

    if (verify_peername || log_certmatch) {

	/*
	 * Verify the dNSName(s) in the peer certificate against the nexthop
	 * and hostname.
	 * 
	 * If DNS names are present, we use the first matching (or else simply
	 * the first) DNS name as the subject CN. The CommonName in the
	 * issuer DN is obsolete when SubjectAltName is available. This
	 * yields much less surprising logs, because we log the name we
	 * verified or a name we checked and failed to match.
	 * 
	 * XXX: The nexthop and host name may both be the same network address
	 * rather than a DNS name. In this case we really should be looking
	 * for GEN_IPADD entries, not GEN_DNS entries.
	 * 
	 * XXX: In ideal world the caller who used the address to build the
	 * connection would tell us that the nexthop is the connection
	 * address, but if that is not practical, we can parse the nexthop
	 * again here.
	 */
	gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
	if (gens) {
	    r = sk_GENERAL_NAME_num(gens);
	    for (i = 0; i < r; ++i) {
		gn = sk_GENERAL_NAME_value(gens, i);
		if (gn->type != GEN_DNS)
		    continue;

		/*
		 * Even if we have an invalid DNS name, we still ultimately
		 * ignore the CommonName, because subjectAltName:DNS is
		 * present (though malformed). Replace any previous peer_CN
		 * if empty or we get a match.
		 * 
		 * We always set at least an empty peer_CN if the ALTNAME cert
		 * flag is set. If not, we set peer_CN from the cert
		 * CommonName below, so peer_CN is always non-null on return.
		 */
		TLScontext->peer_status |= TLS_CERT_FLAG_ALTNAME;
		dnsname = tls_dns_name(gn, TLScontext);
		if (dnsname && *dnsname) {
		    if ((dnsname_match = match_servername(dnsname, props)) != 0)
			matched++;
		    /* Keep the first matched name. */
		    if (TLScontext->peer_CN
			&& ((dnsname_match && matched == 1)
			    || *TLScontext->peer_CN == 0)) {
			myfree(TLScontext->peer_CN);
			TLScontext->peer_CN = 0;
		    }
		    if (verbose)
			msg_info("%s: %ssubjectAltName: %s", props->namaddr,
				 dnsname_match ? "Matched " : "", dnsname);
		}
		if (TLScontext->peer_CN == 0)
		    TLScontext->peer_CN = mystrdup(dnsname ? dnsname : "");
		if (matched && !log_certmatch)
		    break;
	    }
	    if (verify_peername && matched)
		TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED;

	    /*
	     * (Sam Rushing, Ironport) Free stack *and* member GENERAL_NAME
	     * objects
	     */
	    sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
	}

	/*
	 * No subjectAltNames, peer_CN is taken from CommonName.
	 */
	if (TLScontext->peer_CN == 0) {
	    TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);
	    if (*TLScontext->peer_CN)
		matched = match_servername(TLScontext->peer_CN, props);
	    if (verify_peername && matched)
		TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED;
	    if (verbose)
		msg_info("%s %sCommonName %s", props->namaddr,
			 matched ? "Matched " : "", TLScontext->peer_CN);
	} else if (verbose) {
	    char   *tmpcn = tls_peer_CN(peercert, TLScontext);

	    /*
	     * Though the CommonName was superceded by a subjectAltName, log
	     * it when certificate match debugging was requested.
	     */
	    msg_info("%s CommonName %s", TLScontext->namaddr, tmpcn);
	    myfree(tmpcn);
	}
    } else
	TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);

    /*
     * Give them a clue. Problems with trust chain verification are logged
     * when the session is first negotiated, before the session is stored
     * into the cache. We don't want mystery failures, so log the fact the
     * real problem is to be found in the past.
     */
    if (!TLS_CERT_IS_TRUSTED(TLScontext)
	&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
	if (TLScontext->session_reused == 0)
	    tls_log_verify_error(TLScontext);
	else
	    msg_info("%s: re-using session with untrusted certificate, "
		     "look for details earlier in the log", props->namaddr);
    }
}
예제 #20
0
apr_hash_t *serf_ssl_cert_certificate(
    const serf_ssl_certificate_t *cert,
    apr_pool_t *pool)
{
    apr_hash_t *tgt = apr_hash_make(pool);
    unsigned int md_size, i;
    unsigned char md[EVP_MAX_MD_SIZE];
    BIO *bio;
    STACK_OF(GENERAL_NAME) *names;

    /* sha1 fingerprint */
    if (X509_digest(cert->ssl_cert, EVP_sha1(), md, &md_size)) {
        const char hex[] = "0123456789ABCDEF";
        char fingerprint[EVP_MAX_MD_SIZE * 3];

        for (i=0; i<md_size; i++) {
            fingerprint[3*i] = hex[(md[i] & 0xf0) >> 4];
            fingerprint[(3*i)+1] = hex[(md[i] & 0x0f)];
            fingerprint[(3*i)+2] = ':';
        }
        if (md_size > 0)
            fingerprint[(3*(md_size-1))+2] = '\0';
        else
            fingerprint[0] = '\0';

        apr_hash_set(tgt, "sha1", APR_HASH_KEY_STRING,
                     apr_pstrdup(pool, fingerprint));
    }

    /* set expiry dates */
    bio = BIO_new(BIO_s_mem());
    if (bio) {
        ASN1_TIME *notBefore, *notAfter;
        char buf[256];

        memset (buf, 0, sizeof (buf));
        notBefore = X509_get_notBefore(cert->ssl_cert);
        if (ASN1_TIME_print(bio, notBefore)) {
            BIO_read(bio, buf, 255);
            apr_hash_set(tgt, "notBefore", APR_HASH_KEY_STRING,
                         apr_pstrdup(pool, buf));
        }
        memset (buf, 0, sizeof (buf));
        notAfter = X509_get_notAfter(cert->ssl_cert);
        if (ASN1_TIME_print(bio, notAfter)) {
            BIO_read(bio, buf, 255);
            apr_hash_set(tgt, "notAfter", APR_HASH_KEY_STRING,
                         apr_pstrdup(pool, buf));
        }
    }
    BIO_free(bio);

    /* Get subjectAltNames */
    names = X509_get_ext_d2i(cert->ssl_cert, NID_subject_alt_name, NULL, NULL);
    if (names) {
        int names_count = sk_GENERAL_NAME_num(names);

        apr_array_header_t *san_arr = apr_array_make(pool, names_count,
                                                     sizeof(char*));
        apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr);
        for (i = 0; i < names_count; i++) {
            char *p = NULL;
            GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, i);

            switch (nm->type) {
            case GEN_DNS:
                p = apr_pstrmemdup(pool, nm->d.ia5->data, nm->d.ia5->length);
                break;
            default:
                /* Don't know what to do - skip. */
                break;
            }
            if (p) {
                APR_ARRAY_PUSH(san_arr, char*) = p;
            }
        }
        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
    }

    return tgt;
}
예제 #21
0
/**
  @brief Extracts data from a certificate store object.

  @param pCertificate          [in] The certificate to examine.
  @param pIssuer               [out, optional] The issuer name of the certificate.
  @param pSubject              [out, optional] The subject name of the certificate.
  @param pSubjectUri           [out, optional] The subject's URI of the certificate.
  @param pSubjectIP            [out, optional] The subject's IP of the certificate.
  @param pSubjectDNS           [out, optional] The subject's DNS name of the certificate.
  @param pCertThumbprint       [out, optional] The thumbprint of the certificate.
  @param pSubjectHash          [out, optional] The hash code of the certificate.
  @param pCertRawLength        [out, optional] The length of the DER encoded data.
                               can be smaller than the total length of pCertificate in case of chain certificate or garbage follow.
*/
OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_ExtractCertificateData(
    OpcUa_ByteString*           a_pCertificate,
    OpcUa_ByteString*           a_pIssuer,
    OpcUa_ByteString*           a_pSubject,
    OpcUa_ByteString*           a_pSubjectUri,
    OpcUa_ByteString*           a_pSubjectIP,
    OpcUa_ByteString*           a_pSubjectDNS,
    OpcUa_ByteString*           a_pCertThumbprint,
    OpcUa_UInt32*               a_pSubjectHash,
    OpcUa_UInt32*               a_pCertRawLength)
{
    X509*                       pX509Cert = OpcUa_Null;
    char*                       pName = OpcUa_Null;
    GENERAL_NAMES*              pNames = OpcUa_Null;
    const unsigned char*        p;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_ExtractCertificateData");

    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate);

    if(a_pIssuer != OpcUa_Null)
    {
        a_pIssuer->Data = OpcUa_Null;
        a_pIssuer->Length = 0;
    }

    if(a_pSubject != OpcUa_Null)
    {
        a_pSubject->Data = OpcUa_Null;
        a_pSubject->Length = 0;
    }

    if(a_pSubjectUri != OpcUa_Null)
    {
        a_pSubjectUri->Data = OpcUa_Null;
        a_pSubjectUri->Length = 0;
    }

    if(a_pSubjectIP != OpcUa_Null)
    {
        a_pSubjectIP->Data = OpcUa_Null;
        a_pSubjectIP->Length = 0;
    }

    if(a_pSubjectDNS != OpcUa_Null)
    {
        a_pSubjectDNS->Data = OpcUa_Null;
        a_pSubjectDNS->Length = 0;
    }

    if(a_pCertThumbprint != OpcUa_Null)
    {
        a_pCertThumbprint->Data = OpcUa_Null;
        a_pCertThumbprint->Length = 0;
    }

    if(a_pSubjectHash != OpcUa_Null)
    {
        *a_pSubjectHash = 0;
    }

    if(a_pCertRawLength != OpcUa_Null)
    {
        *a_pCertRawLength = 0;
    }

    /* convert openssl X509 certificate to DER encoded bytestring certificate */
    p = a_pCertificate->Data;
    if(!(pX509Cert = d2i_X509((X509**)OpcUa_Null, &p, a_pCertificate->Length)))
    {
        uStatus = OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(a_pIssuer != OpcUa_Null)
    {
        pName = X509_NAME_oneline(X509_get_issuer_name(pX509Cert), NULL, 0);
        OpcUa_GotoErrorIfAllocFailed(pName);
        a_pIssuer->Length = strlen(pName)+1;
        a_pIssuer->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pIssuer->Length*sizeof(OpcUa_Byte));
        OpcUa_GotoErrorIfAllocFailed(a_pIssuer->Data);
        uStatus = OpcUa_P_Memory_MemCpy(a_pIssuer->Data, a_pIssuer->Length, pName, a_pIssuer->Length);
        OpcUa_GotoErrorIfBad(uStatus);
        OPENSSL_free(pName);
        pName = OpcUa_Null;
    }

    if(a_pSubject != OpcUa_Null)
    {
        pName = X509_NAME_oneline(X509_get_subject_name(pX509Cert), NULL, 0);
        OpcUa_GotoErrorIfAllocFailed(pName);
        a_pSubject->Length = strlen(pName)+1;
        a_pSubject->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pSubject->Length*sizeof(OpcUa_Byte));
        OpcUa_GotoErrorIfAllocFailed(a_pSubject->Data);
        uStatus = OpcUa_P_Memory_MemCpy(a_pSubject->Data, a_pSubject->Length, pName, a_pSubject->Length);
        OpcUa_GotoErrorIfBad(uStatus);
        OPENSSL_free(pName);
        pName = OpcUa_Null;
    }

    if(a_pSubjectUri != OpcUa_Null || a_pSubjectIP != OpcUa_Null || a_pSubjectDNS != OpcUa_Null)
    {
        pNames = X509_get_ext_d2i(pX509Cert, NID_subject_alt_name, OpcUa_Null, OpcUa_Null);
        if (pNames != OpcUa_Null)
        {
            int num;
            for (num = 0; num < sk_GENERAL_NAME_num(pNames); num++)
            {
                GENERAL_NAME *value = sk_GENERAL_NAME_value(pNames, num);
                switch (value->type)
                {
                case GEN_URI:
                    if (a_pSubjectUri != OpcUa_Null && a_pSubjectUri->Data == OpcUa_Null)
                    {
                        a_pSubjectUri->Length = value->d.ia5->length+1;
                        a_pSubjectUri->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pSubjectUri->Length*sizeof(OpcUa_Byte));
                        OpcUa_GotoErrorIfAllocFailed(a_pSubjectUri->Data);
                        uStatus = OpcUa_P_Memory_MemCpy(a_pSubjectUri->Data, a_pSubjectUri->Length, value->d.ia5->data, a_pSubjectUri->Length);
                        OpcUa_GotoErrorIfBad(uStatus);
                    }
                break;

                case GEN_IPADD:
                    if (a_pSubjectIP != OpcUa_Null && a_pSubjectIP->Data == OpcUa_Null)
                    {
                        a_pSubjectIP->Length = value->d.ip->length;
                        a_pSubjectIP->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pSubjectIP->Length*sizeof(OpcUa_Byte));
                        OpcUa_GotoErrorIfAllocFailed(a_pSubjectIP->Data);
                        uStatus = OpcUa_P_Memory_MemCpy(a_pSubjectIP->Data, a_pSubjectIP->Length, value->d.ip->data, a_pSubjectIP->Length);
                        OpcUa_GotoErrorIfBad(uStatus);
                    }
                break;

                case GEN_DNS:
                    if (a_pSubjectDNS != OpcUa_Null && a_pSubjectDNS->Data == OpcUa_Null)
                    {
                        a_pSubjectDNS->Length = value->d.ia5->length+1;
                        a_pSubjectDNS->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pSubjectDNS->Length*sizeof(OpcUa_Byte));
                        OpcUa_GotoErrorIfAllocFailed(a_pSubjectDNS->Data);
                        uStatus = OpcUa_P_Memory_MemCpy(a_pSubjectDNS->Data, a_pSubjectDNS->Length, value->d.ia5->data, a_pSubjectDNS->Length);
                        OpcUa_GotoErrorIfBad(uStatus);
                    }
                break;
                }
            }
            sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
            pNames = OpcUa_Null;
        }
    }

    if(a_pCertThumbprint != OpcUa_Null)
    {
        /* update pX509Cert->sha1_hash */
        X509_check_purpose(pX509Cert, -1, 0);
        a_pCertThumbprint->Length = sizeof(pX509Cert->sha1_hash);
        a_pCertThumbprint->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pCertThumbprint->Length*sizeof(OpcUa_Byte));
        OpcUa_GotoErrorIfAllocFailed(a_pCertThumbprint->Data);
        uStatus = OpcUa_P_Memory_MemCpy(a_pCertThumbprint->Data, a_pCertThumbprint->Length, pX509Cert->sha1_hash, a_pCertThumbprint->Length);
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(a_pSubjectHash != OpcUa_Null)
    {
        *a_pSubjectHash = X509_NAME_hash(X509_get_subject_name(pX509Cert));
    }

    if(a_pCertRawLength != OpcUa_Null)
    {
        *a_pCertRawLength = (OpcUa_UInt32)(p - a_pCertificate->Data);
    }

    X509_free(pX509Cert);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(a_pIssuer != OpcUa_Null && a_pIssuer->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pIssuer->Data);
        a_pIssuer->Data = OpcUa_Null;
        a_pIssuer->Length = 0;
    }

    if(a_pSubject != OpcUa_Null && a_pSubject->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pSubject->Data);
        a_pSubject->Data = OpcUa_Null;
        a_pSubject->Length = 0;
    }

    if(a_pSubjectUri != OpcUa_Null && a_pSubjectUri->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pSubjectUri->Data);
        a_pSubjectUri->Data = OpcUa_Null;
        a_pSubjectUri->Length = 0;
    }

    if(a_pSubjectIP != OpcUa_Null && a_pSubjectIP->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pSubjectIP->Data);
        a_pSubjectIP->Data = OpcUa_Null;
        a_pSubjectIP->Length = 0;
    }

    if(a_pSubjectDNS != OpcUa_Null && a_pSubjectDNS->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pSubjectDNS->Data);
        a_pSubjectDNS->Data = OpcUa_Null;
        a_pSubjectDNS->Length = 0;
    }

    if(a_pCertThumbprint != OpcUa_Null && a_pCertThumbprint->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pCertThumbprint->Data);
        a_pCertThumbprint->Data = OpcUa_Null;
        a_pCertThumbprint->Length = 0;
    }

    if (pName != OpcUa_Null)
    {
        OPENSSL_free(pName);
    }

    if (pNames != OpcUa_Null)
    {
        sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
    }

    if(pX509Cert != OpcUa_Null)
    {
        X509_free(pX509Cert);
    }

OpcUa_FinishErrorHandling;
}
예제 #22
0
파일: tcptls.c 프로젝트: auntieNeo/asterisk
/*! \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

	/* TCP/TLS connections are associated with external protocols, and
	 * should not be allowed to execute 'dangerous' functions. This may
	 * need to be pushed down into the individual protocol handlers, but
	 * this seems like a good general policy.
	 */
	if (ast_thread_inhibit_escalations()) {
		ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection\n");
		ast_tcptls_close_session_file(tcptls_session);
		ao2_ref(tcptls_session, -1);
		return NULL;
	}

	tcptls_session->stream_cookie = tcptls_stream_alloc();
	if (!tcptls_session->stream_cookie) {
		ast_tcptls_close_session_file(tcptls_session);
		ao2_ref(tcptls_session, -1);
		return NULL;
	}

	/*
	* open a FILE * as appropriate.
	*/
	if (!tcptls_session->parent->tls_cfg) {
		tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, NULL,
			tcptls_session->fd, -1);
		if (tcptls_session->f) {
			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_log(LOG_ERROR, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
		} else if ((tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie,
			tcptls_session->ssl, tcptls_session->fd, -1))) {
			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;
					X509_NAME *name = X509_get_subject_name(peer);
					STACK_OF(GENERAL_NAME) *alt_names;
					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));
						if (!check_tcptls_cert_name(str, tcptls_session->parent->hostname, "common name")) {
							found = 1;
							break;
						}
					}

					if (!found) {
						alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL);
						if (alt_names != NULL) {
							int alt_names_count = sk_GENERAL_NAME_num(alt_names);

							for (pos = 0; pos < alt_names_count; pos++) {
								const GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(alt_names, pos);

								if (alt_name->type != GEN_DNS) {
									continue;
								}

								if (!check_tcptls_cert_name(alt_name->d.dNSName, tcptls_session->parent->hostname, "alt name")) {
									found = 1;
									break;
								}
							}

							sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
						}
					}

					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_ERROR, "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;
	}
}
예제 #23
0
static int get_subjectAltName(X509 *s_ctx)
{
    int error_code = 0;
    GENERAL_NAMES *gens = NULL;
    GENERAL_NAME *gen = NULL;
  
    char *altname;
    unsigned char p[5], *ip;

    gens = X509_get_ext_d2i(s_ctx, NID_subject_alt_name, NULL, NULL);

    if(NULL == gens)
    {
        error_code = 0;
        goto end;
    }

    int gen_num = sk_GENERAL_NAME_num(gens);

    int i=0;
    for(i=0; i <= gen_num; ++i)
    {
        gen = sk_GENERAL_NAME_value(gens, i);
        if(NULL == gen)
        {
            continue;
        }

        if (gen->type == GEN_DNS 
        ||gen->type == GEN_EMAIL 
        ||gen->type == GEN_URI )
        {
            // make sure if the data is terminated by '\0'. 
            if (gen->d.ia5->data[gen->d.ia5->length] != '\0') 
            {
                continue;
            }

            altname = (char *)malloc(gen->d.ia5->length + 1);

            strncpy(altname, (char *) gen->d.ia5->data, (gen->d.ia5->length + 1));

            switch (gen->type) {
            case GEN_EMAIL:
                printf("email:%s\n", altname);
                break;
            case GEN_DNS:
                printf("DNS:%s\n", altname);
                break;
            case GEN_URI:
            default:
                printf("URI:%s\n", altname);
                break;    
            }
        }
        else if (gen->type == GEN_IPADD)
        {
            if (gen->d.ip->length != 4) {
                continue;
              }
            ip = p;
            ip = gen->d.ip->data;
            printf("IP:%u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
        }


        if(altname)
        {
            free(altname);
            altname = NULL;
        }     
    }

end:
    if(gens)
    {
        // GENERAL_NAMES_free(gens);
        sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
    }

    return error_code;
}
예제 #24
0
static int get_alt(str* res, int local, int type, sip_msg_t* msg)
{
	static char buf[1024];
	int n, found = 0;
	STACK_OF(GENERAL_NAME)* names = 0;
	GENERAL_NAME* nm;
	X509* cert;
	struct tcp_connection* c;
	str text;
	struct ip_addr ip;

	if (get_cert(&cert, &c, msg, local) < 0) return -1;

	names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
	if (!names) {
		DBG("Cannot get certificate alternative subject\n");
		goto err;

	}

	for (n = 0; n < sk_GENERAL_NAME_num(names); n++) {
		nm = sk_GENERAL_NAME_value(names, n);
		if (nm->type != type) continue;
		switch(type) {
		case GEN_EMAIL:
		case GEN_DNS:
		case GEN_URI:
			text.s = (char*)nm->d.ia5->data;
			text.len = nm->d.ia5->length;
			if (text.len >= 1024) {
				ERR("Alternative subject text too long\n");
				goto err;
			}
			memcpy(buf, text.s, text.len);
			res->s = buf;
			res->len = text.len;
			found = 1;
			break;

		case GEN_IPADD:
			ip.len = nm->d.iPAddress->length;
			ip.af = (ip.len == 16) ? AF_INET6 : AF_INET;
			memcpy(ip.u.addr, nm->d.iPAddress->data, ip.len);
			text.s = ip_addr2a(&ip);
			text.len = strlen(text.s);
			memcpy(buf, text.s, text.len);
			res->s = buf;
			res->len = text.len;
			found = 1;
			break;
		}
		break;
	}
	if (!found) goto err;

	if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
	if (!local) X509_free(cert);
	tcpconn_put(c);
	return 0;
 err:
	if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
	if (!local) X509_free(cert);
	tcpconn_put(c);
	return -1;
}
예제 #25
0
static int
set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx, CONF_VALUE *cnf)
{
	STACK_OF(GENERAL_NAME) *fnm = NULL;
	STACK_OF(X509_NAME_ENTRY) *rnm = NULL;

	if (!strncmp(cnf->name, "fullname", 9)) {
		fnm = gnames_from_sectname(ctx, cnf->value);
		if (!fnm)
			goto err;
	} else if (!strcmp(cnf->name, "relativename")) {
		int ret;
		STACK_OF(CONF_VALUE) *dnsect;
		X509_NAME *nm;
		nm = X509_NAME_new();
		if (!nm)
			return -1;
		dnsect = X509V3_get_section(ctx, cnf->value);
		if (!dnsect) {
			X509V3err(X509V3_F_SET_DIST_POINT_NAME,
			    X509V3_R_SECTION_NOT_FOUND);
			return -1;
		}
		ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC);
		X509V3_section_free(ctx, dnsect);
		rnm = nm->entries;
		nm->entries = NULL;
		X509_NAME_free(nm);
		if (!ret || sk_X509_NAME_ENTRY_num(rnm) <= 0)
			goto err;
		/* Since its a name fragment can't have more than one
		 * RDNSequence
		 */
		if (sk_X509_NAME_ENTRY_value(rnm,
		    sk_X509_NAME_ENTRY_num(rnm) - 1)->set) {
			X509V3err(X509V3_F_SET_DIST_POINT_NAME,
			    X509V3_R_INVALID_MULTIPLE_RDNS);
			goto err;
		}
	} else
		return 0;

	if (*pdp) {
		X509V3err(X509V3_F_SET_DIST_POINT_NAME,
		    X509V3_R_DISTPOINT_ALREADY_SET);
		goto err;
	}

	*pdp = DIST_POINT_NAME_new();
	if (!*pdp)
		goto err;
	if (fnm) {
		(*pdp)->type = 0;
		(*pdp)->name.fullname = fnm;
	} else {
		(*pdp)->type = 1;
		(*pdp)->name.relativename = rnm;
	}

	return 1;

err:
	if (fnm)
		sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free);
	if (rnm)
		sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free);
	return -1;
}
예제 #26
0
static int
imap_check_server_identity(SSL *ssl, const char *host,
                           ImapUserCb user_cb, void *user_arg)
{
  long vfy_result;
  X509 *cert;
  X509_NAME *subj;
  int ok, host_len;
  gchar *colon;
  int has_extension_with_dns_name = 0;
  STACK_OF(GENERAL_NAME) *altnames;

  if(!host)
    return 0;
  /* Check whether the certificate matches the server. */
  cert = SSL_get_peer_certificate(ssl);
  if(!cert)
    return 0;

  colon = strchr(host, ':');
  host_len = colon ? colon - host : (int)strlen(host);
  ok = 0;

  altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);

  if (altnames) {
    int i;

    for (i=0; i< sk_GENERAL_NAME_num(altnames); i++) {
      const GENERAL_NAME *name = sk_GENERAL_NAME_value(altnames, i);

      /* We handle only GEN_DNS. GEN_IP (certificates for IP numbers)
         are too weird to be real in IMAP case. */
      if (name->type == GEN_DNS) {
        const ASN1_IA5STRING *ia5 = name->d.ia5;
        const char *name = (const char*)ia5->data;
        has_extension_with_dns_name = 1;

        if (strlen(name) == (size_t)ia5->length &&
            host_matches_domain(host, name, host_len)) {
          /* printf("verified name using extension\n"); */
          ok = 1;
          break;
        }
      }
    }
    sk_GENERAL_NAME_pop_free(altnames, GENERAL_NAME_free);
  }

  if (!has_extension_with_dns_name) {
    char data[256];
    size_t name_len;
    if( (subj = X509_get_subject_name(cert)) &&
        (name_len = 
         X509_NAME_get_text_by_NID(subj, NID_commonName,
                                   data, sizeof(data)))){
      data[sizeof(data)-1] = 0;

      /* Remember to check whether there was no truncation or NUL
         characters embedded in the text. */
      if(name_len == strlen(data) &&
         host_matches_domain(host, data, host_len)) {
        ok =1;
        /* printf("verified name using common name\n"); */
      }
    }
  }

  X509_free(cert);
  if(ok)
    vfy_result = SSL_get_verify_result(ssl);
  else
    vfy_result = X509_V_ERR_APPLICATION_VERIFICATION;

  if(vfy_result == X509_V_OK)
    return 1;
  /* There was a problem with the verification, one has to leave it up
   * to the application what to do with this.
   */
  ok = 0;
  if(user_cb)
    user_cb(IME_TLS_VERIFY_ERROR, user_arg, &ok, 
            vfy_result, ssl);
  return ok;
}
예제 #27
0
/* See RFC 5280 section 4.2.1.6 for SubjectAltName details. */
static int
tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name)
{
	STACK_OF(GENERAL_NAME) *altname_stack = NULL;
	union tls_addr addrbuf;
	int addrlen, type;
	int count, i;
	int rv = -1;

	altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name,
	    NULL, NULL);
	if (altname_stack == NULL)
		return -1;

	if (inet_pton(AF_INET, name, &addrbuf) == 1) {
		type = GEN_IPADD;
		addrlen = 4;
	} else if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
		type = GEN_IPADD;
		addrlen = 16;
	} else {
		type = GEN_DNS;
		addrlen = 0;
	}

	count = sk_GENERAL_NAME_num(altname_stack);
	for (i = 0; i < count; i++) {
		GENERAL_NAME	*altname;

		altname = sk_GENERAL_NAME_value(altname_stack, i);

		if (altname->type != type)
			continue;

		if (type == GEN_DNS) {
			const void	*data;
			int		 format, len;

			format = ASN1_STRING_type(altname->d.dNSName);
			if (format == V_ASN1_IA5STRING) {
				data = ASN1_STRING_get0_data(altname->d.dNSName);
				len = ASN1_STRING_length(altname->d.dNSName);

				if (len < 0 || len != (int)strlen(data)) {
					tls_set_errorx(ctx,
					    "error verifying name '%s': "
					    "NUL byte in subjectAltName, "
					    "probably a malicious certificate",
					    name);
					rv = -2;
					break;
				}

				/*
				 * Per RFC 5280 section 4.2.1.6:
				 * " " is a legal domain name, but that
				 * dNSName must be rejected.
				 */
				if (strcmp(data, " ") == 0) {
					tls_set_error(ctx,
					    "error verifying name '%s': "
					    "a dNSName of \" \" must not be "
					    "used", name);
					rv = -2;
					break;
				}

				if (tls_match_name(data, name) == 0) {
					rv = 0;
					break;
				}
			} else {
#ifdef DEBUG
				fprintf(stdout, "%s: unhandled subjectAltName "
				    "dNSName encoding (%d)\n", getprogname(),
				    format);
#endif
			}

		} else if (type == GEN_IPADD) {
			const unsigned char *data;
			int		 datalen;

			datalen = ASN1_STRING_length(altname->d.iPAddress);
			data = ASN1_STRING_get0_data(altname->d.iPAddress);

			if (datalen < 0) {
				tls_set_errorx(ctx,
				    "Unexpected negative length for an "
				    "IP address: %d", datalen);
				rv = -2;
				break;
			}

			/*
			 * Per RFC 5280 section 4.2.1.6:
			 * IPv4 must use 4 octets and IPv6 must use 16 octets.
			 */
			if (datalen == addrlen &&
			    memcmp(data, &addrbuf, addrlen) == 0) {
				rv = 0;
				break;
			}
		}
	}

	sk_GENERAL_NAME_pop_free(altname_stack, GENERAL_NAME_free);
	return rv;
}
예제 #28
0
int tlsops_alt(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	static char buf[1024];
	int type = GEN_URI, my = 0, n, found = 0, ind_local;
	STACK_OF(GENERAL_NAME)* names = 0;
	GENERAL_NAME* nm;
	X509* cert;
	struct tcp_connection* c;
	str text;
	struct ip_addr ip;

	ind_local = param->pvn.u.isname.name.n;

	if (ind_local & CERT_PEER) {
		my = 0;
		ind_local = ind_local ^ CERT_PEER;
	} else if (ind_local & CERT_LOCAL) {
		my = 1;
		ind_local = ind_local ^ CERT_LOCAL;
	} else {
		LM_CRIT("could not determine certificate\n");
		return pv_get_null(msg, param, res);
	}

	switch(ind_local) {
		case COMP_E:    type = GEN_EMAIL; break;
		case COMP_HOST: type = GEN_DNS;   break;
		case COMP_URI:  type = GEN_URI;   break;
		case COMP_IP:   type = GEN_IPADD; break;
		default:
			LM_CRIT("ind_local=%d\n", ind_local);
			return pv_get_null(msg, param, res);
	}

	if (get_cert(&cert, &c, msg, my) < 0) return -1;

	names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
	if (!names) {
		LM_ERR("cannot get certificate alternative subject\n");
		goto err;

	}

	for (n = 0; n < sk_GENERAL_NAME_num(names); n++) {
		nm = sk_GENERAL_NAME_value(names, n);
		if (nm->type != type) continue;
		switch(type) {
		case GEN_EMAIL:
		case GEN_DNS:
		case GEN_URI:
			text.s = (char*)nm->d.ia5->data;
			text.len = nm->d.ia5->length;
			if (text.len >= 1024) {
				LM_ERR("alternative subject text too long\n");
				goto err;
			}
			memcpy(buf, text.s, text.len);
			res->rs.s = buf;
			res->rs.len = text.len;
			res->flags = PV_VAL_STR;
			found = 1;
			break;

		case GEN_IPADD:
			ip.len = nm->d.iPAddress->length;
			ip.af = (ip.len == 16) ? AF_INET6 : AF_INET;
			memcpy(ip.u.addr, nm->d.iPAddress->data, ip.len);
			text.s = ip_addr2a(&ip);
			text.len = strlen(text.s);
			memcpy(buf, text.s, text.len);
			res->rs.s = buf;
			res->rs.len = text.len;
			res->flags = PV_VAL_STR;
			found = 1;
			break;
		}
		break;
	}
	if (!found) goto err;

	if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return 0;
 err:
	if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return pv_get_null(msg, param, res);
}
예제 #29
0
파일: OsSSL.cpp 프로젝트: LordGaav/sipxecs
/* Get the validated names for the connection peer.
 *
 * Usually, the names in the altNames will be easier to parse and use than commonName
 * Returns
 * - true if the connection peer is validated by a trusted authority
 * - false if not, in which case no names are returned.
 */
bool OsSSL::peerIdentity( SSL*       connection ///< SSL connection to be described
                         ,UtlSList*  altNames   /**< UtlStrings for verfied subjectAltNames
                                                 *   are added to this - caller must free them.
                                                 */
                         ,UtlString* commonName ///< the Subject name is returned here
                         )
{
   bool peerCertTrusted = false;

#  ifdef TEST_DEBUG
   UtlString debugMsg;
#  endif

   if (altNames)
   {
      altNames->destroyAll();
   }
   if (commonName)
   {
      commonName->remove(0);
   }

   if (connection)
   {
      // Extract the subject and issuer information about the peer
      // and the certificate validation result.  Neither of these
      // are meaningful without the other.
      //    (note various dynamically allocated items - freed below)
      X509* peer_cert = SSL_get_peer_certificate(connection);
      if (peer_cert)
      {
         if (X509_V_OK == SSL_get_verify_result(connection))
         {
            peerCertTrusted = true;

            char* subjectStr = X509_NAME_oneline(X509_get_subject_name(peer_cert),NULL,0);

            // @TODO this should also enforce any extendedKeyUsage limitations

#           ifdef TEST_DEBUG
            debugMsg.append("OsSSL::peerIdentity verified");
#           endif
            if (subjectStr)
            {
               // this should always be true, I think...
               if (commonName)
               {
                  commonName->append(subjectStr);
               }

#              ifdef TEST_DEBUG
               debugMsg.append(" '");
               debugMsg.append(subjectStr);
               debugMsg.append("'");
#              endif
               OPENSSL_free(subjectStr);
            }

            if (altNames)
            {
               // Look for the subjectAltName attributes
               GENERAL_NAMES* names;
               names = (GENERAL_NAMES*)X509_get_ext_d2i(peer_cert, NID_subject_alt_name, NULL, NULL);

               for(int i = 0; i < sk_GENERAL_NAME_num(names); i++)
               {
                  GENERAL_NAME*   name = sk_GENERAL_NAME_value(names, i);
                  ASN1_IA5STRING* nameValue;
                  UtlString*      normalizedName;

                  switch (name->type)
                  {
                  case GEN_DNS:
                  case GEN_URI:
                     nameValue = name->d.uniformResourceIdentifier;
                     normalizedName
                        = new UtlString((const char*)(nameValue->data),nameValue->length);
                     // @TODO: We should parse this value before adjusting the case,
                     //        but that requires doing it at a higher level in the stack
                     //        where we can parse a URL, and we don't yet have selection
                     //        based on type anyway.
                     normalizedName->toLower();
#                    ifdef TEST_DEBUG
                     debugMsg.append(" '");
                     debugMsg.append(*normalizedName);
                     debugMsg.append("'");
#                    endif
                     altNames->append(normalizedName);
                     break;

                  default:
                     // don't care about any other values
                     break;
                  }
               }
               sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
            }
#           ifdef TEST_DEBUG
            OsSysLog::add(FAC_KERNEL, PRI_DEBUG, "%s", debugMsg.data());
#           endif
         }
         else
         {
            OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsSSL::peerIdentity peer not validated");
         }

         X509_free(peer_cert);
      }
      else
      {
         OsSysLog::add(FAC_KERNEL, PRI_WARNING, "OsSSL::peerIdentity no peer certificate");
      }
   }
   else
   {
      OsSysLog::add(FAC_KERNEL, PRI_CRIT, "OsSSL::peerIdentity called with NULL connection");
   }

   return peerCertTrusted;
}
예제 #30
0
파일: checks.c 프로젝트: kroeckx/x509lint
static void CheckSAN(X509 *x509, CertType type)
{
	int idx = -1;
	bool bSanFound = false;
	bool bSanName = false;
	bool bSanRequired = false;
	bool bCommonNameFound = false;
	ASN1_STRING *commonName = NULL;
	enum { SAN_TYPE_NOT_ALLOWED, SAN_TYPE_ALLOWED, SAN_TYPE_WARN } name_type_allowed[GEN_RID+1];

	for (int i = 0; i < GEN_RID+1; i++)
	{
		name_type_allowed[i] = SAN_TYPE_NOT_ALLOWED;
	}

	if (GetBit(cert_info, CERT_INFO_SERV_AUTH) || GetBit(cert_info, CERT_INFO_ANY_EKU) || GetBit(cert_info, CERT_INFO_NO_EKU))
	{
		name_type_allowed[GEN_DNS] = SAN_TYPE_ALLOWED;
		name_type_allowed[GEN_IPADD] = SAN_TYPE_ALLOWED;
		bSanRequired = true;
	}
	if (GetBit(cert_info, CERT_INFO_EMAIL) || GetBit(cert_info, CERT_INFO_ANY_EKU) || GetBit(cert_info, CERT_INFO_NO_EKU))
	{
		name_type_allowed[GEN_EMAIL] = SAN_TYPE_ALLOWED;
		bSanRequired = true;
	}
	if (GetBit(cert_info, CERT_INFO_CLIENT_AUTH))
	{
		/*
		 * DNS and IP address doesn't make sense for a TLS client that
		 * doesn't also do server authentication.
		 */
		if (name_type_allowed[GEN_DNS] == SAN_TYPE_NOT_ALLOWED)
		{
			name_type_allowed[GEN_DNS] = SAN_TYPE_WARN;
			name_type_allowed[GEN_IPADD] = SAN_TYPE_WARN;
		}
		name_type_allowed[GEN_EMAIL] = SAN_TYPE_ALLOWED;
	}
	if (GetBit(warnings, WARN_UNKNOWN_EKU) && !GetBit(cert_info, CERT_INFO_SERV_AUTH) && !GetBit(cert_info, CERT_INFO_ANY_EKU))
	{
		/*
		 * If it's a certificate with an unknown EKU that isn't
		 * also valid for server auth, allow the other types
		 */
		name_type_allowed[GEN_OTHERNAME] = SAN_TYPE_ALLOWED;
		name_type_allowed[GEN_X400] = SAN_TYPE_ALLOWED;
		name_type_allowed[GEN_EDIPARTY] = SAN_TYPE_ALLOWED;
		name_type_allowed[GEN_URI] = SAN_TYPE_ALLOWED;
	}

	X509_NAME *subject = X509_get_subject_name(x509);
	for (int i = 0; i < X509_NAME_entry_count(subject); i++)
	{
		X509_NAME_ENTRY *ne = X509_NAME_get_entry(subject, i);
		ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(ne);

		if (OBJ_cmp(obj_commonName, obj) == 0)
		{
			commonName = X509_NAME_ENTRY_get_data(ne);
			break;
		}
	}

	do
	{
		int critical = -1;

		GENERAL_NAMES *names = X509_get_ext_d2i(x509, NID_subject_alt_name, &critical, &idx);

		if (names == NULL)
		{
			if (critical >= 0)
			{
				/* Found but fails to parse */
				SetError(ERR_INVALID);
				bSanFound = true;
				continue;
			}
			/* Not found */
			break;
		}
		for (int i = 0; i < sk_GENERAL_NAME_num(names); i++)
		{
			GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
			int type;
			ASN1_STRING *name_s = GENERAL_NAME_get0_value(name, &type);
			if (type > GEN_RID || type < 0)
			{
				SetError(ERR_INVALID);
			}
			else if (name_type_allowed[type] == SAN_TYPE_NOT_ALLOWED)
			{
				SetError(ERR_SAN_TYPE);
			}
			else if (name_type_allowed[type] == SAN_TYPE_WARN)
			{
				SetWarning(WARN_TLS_CLIENT_DNS);
			}
			if (type == GEN_DNS)
			{
				for (int j = i+1; j < sk_GENERAL_NAME_num(names); j++)
				{
					GENERAL_NAME *name2 = sk_GENERAL_NAME_value(names, j);
					int type2;
					ASN1_STRING *name2_s = GENERAL_NAME_get0_value(name2, &type2);
					if (type == type2 && ASN1_STRING_cmpcase(name_s, name2_s) == 0)
					{
						SetWarning(WARN_DUPLICATE_SAN);
					}
				}

				char *s = malloc(name_s->length + 1);
				strncpy(s, (char *)name_s->data, name_s->length);
				s[name_s->length] = '\0';

				unsigned char buf[sizeof(struct in6_addr)];
				if (inet_pton(AF_INET, s, buf) == 1 || inet_pton(AF_INET6, s, buf) == 1)
				{
					SetError(ERR_IP_IN_DNSNAME);
				}
				free(s);
			}
			if ((type == GEN_DNS || type == GEN_EMAIL) && commonName != NULL)
			{
				if (ASN1_STRING_cmpcase(name_s, commonName) == 0)
				{
					bCommonNameFound = true;
				}
			}
			if (type == GEN_IPADD)
			{
				int af = AF_UNSPEC;
				if (name_s->length == 4)
				{
					af = AF_INET;
				}
				else if (name_s->length == 16)
				{
					af = AF_INET6;
				}
				else
				{
					SetError(ERR_IP_FAMILY);
				}
				if (af != AF_UNSPEC && commonName != NULL)
				{
					unsigned char buf[sizeof(struct in6_addr)];
					char *s = malloc(commonName->length + 1);

					strncpy(s, (char *)commonName->data, commonName->length);
					s[commonName->length] = '\0';

					inet_pton(af, s, buf);

					/* We want to compare them binary, the string version is not standard. */
					if (memcmp(buf, name_s->data, name_s->length) == 0)
					{
						bCommonNameFound = true;
					}
					free(s);
				}
			}
			CheckGeneralNameType(name);
			bSanName = true;
		}
		sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
		bSanFound = true;
	}
	while (1);

	if (!bSanFound && bSanRequired)
	{
		/* Required by CAB base 7.1.4.2.1 */
		if (type == SubscriberCertificate)
		{
			SetError(ERR_NO_SUBJECT_ALT_NAME);
		}
	}
	if (bSanFound && !bSanName)
	{
		SetError(ERR_SAN_WITHOUT_NAME);
	}
	if (commonName != NULL && bSanFound && !bCommonNameFound)
	{
//		SetError(ERR_CN_NOT_IN_SAN);
	}
}