示例#1
0
文件: pgp.c 项目: uvbs/SupportCenter
/**
  * gnutls_openpgp_key_check_hostname - This function compares the given hostname with the hostname in the key
  * @key: should contain an gnutls_openpgp_key_t structure
  * @hostname: A null terminated string that contains a DNS name
  *
  * This function will check if the given key's owner matches
  * the given hostname. This is a basic implementation of the matching 
  * described in RFC2818 (HTTPS), which takes into account wildcards.
  *
  * Returns non zero on success, and zero on failure.
  *
  **/
int
gnutls_openpgp_key_check_hostname (gnutls_openpgp_key_t key,
				   const char *hostname)
{

  char dnsname[MAX_CN];
  size_t dnsnamesize;
  int ret = 0;
  int i = 0;

  /* Check through all included names.
   */
  for (i = 0; !(ret < 0); i++)
    {

      dnsnamesize = sizeof (dnsname);
      ret = gnutls_openpgp_key_get_name (key, i, dnsname, &dnsnamesize);

      if (_gnutls_hostname_compare (dnsname, hostname))
	{
	  return 1;
	}
    }

  /* not found a matching name
   */
  return 0;
}
示例#2
0
/* compare hostname against certificate, taking account of wildcards
 * return 1 on success or 0 on error
 *
 * note: certnamesize is required as X509 certs can contain embedded NULs in
 * the strings such as CN or subjectAltName.
 *
 * @level: is used for recursion. Use 0 when you call this function.
 */
int
_gnutls_hostname_compare (const char *certname,
                          size_t certnamesize, const char *hostname, int level)
{

  if (level > 5)
    return 0;

  /* find the first different character */
  for (; *certname && *hostname && c_toupper (*certname) == c_toupper (*hostname);
       certname++, hostname++, certnamesize--)
    ;

  /* the strings are the same */
  if (certnamesize == 0 && *hostname == '\0')
    return 1;

  if (*certname == '*')
    {
      /* a wildcard certificate */

      certname++;
      certnamesize--;

      while (1)
        {
          /* Use a recursive call to allow multiple wildcards */
          if (_gnutls_hostname_compare (certname, certnamesize, hostname, level+1))
            return 1;

          /* wildcards are only allowed to match a single domain
             component or component fragment */
          if (*hostname == '\0' || *hostname == '.')
            break;
          hostname++;
        }

      return 0;
    }

  return 0;
}
示例#3
0
/**
 * gnutls_x509_crt_check_hostname:
 * @cert: should contain an gnutls_x509_crt_t structure
 * @hostname: A null terminated string that contains a DNS name
 *
 * This function will check if the given certificate's subject matches
 * the given hostname.  This is a basic implementation of the matching
 * described in RFC2818 (HTTPS), which takes into account wildcards,
 * and the DNSName/IPAddress subject alternative name PKIX extension.
 *
 * Returns: non-zero for a successful match, and zero on failure.
 **/
int
gnutls_x509_crt_check_hostname (gnutls_x509_crt_t cert, const char *hostname)
{

  char dnsname[MAX_CN];
  size_t dnsnamesize;
  int found_dnsname = 0;
  int ret = 0;
  int i = 0;

  /* try matching against:
   *  1) a DNS name as an alternative name (subjectAltName) extension
   *     in the certificate
   *  2) the common name (CN) in the certificate
   *
   *  either of these may be of the form: *.domain.tld
   *
   *  only try (2) if there is no subjectAltName extension of
   *  type dNSName
   */

  /* Check through all included subjectAltName extensions, comparing
   * against all those of type dNSName.
   */
  for (i = 0; !(ret < 0); i++)
    {

      dnsnamesize = sizeof (dnsname);
      ret = gnutls_x509_crt_get_subject_alt_name (cert, i,
                                                  dnsname, &dnsnamesize,
                                                  NULL);

      if (ret == GNUTLS_SAN_DNSNAME)
        {
          found_dnsname = 1;
          if (_gnutls_hostname_compare (dnsname, dnsnamesize, hostname, 0))
            {
              return 1;
            }
        }
    }

  if (!found_dnsname)
    {
      /* not got the necessary extension, use CN instead
       */
      dnsnamesize = sizeof (dnsname);
      if (gnutls_x509_crt_get_dn_by_oid (cert, OID_X520_COMMON_NAME, 0,
                                         0, dnsname, &dnsnamesize) < 0)
        {
          /* got an error, can't find a name
           */
          return 0;
        }

      if (_gnutls_hostname_compare (dnsname, dnsnamesize, hostname, 0))
        {
          return 1;
        }
    }

  /* not found a matching name
   */
  return 0;
}
/**
 * From gnutls and spice red_peer.c
 * TODO: switch to gnutls and get rid of this
 *
 * This function will check if the given certificate's subject matches
 * the given hostname.  This is a basic implementation of the matching
 * described in RFC2818 (HTTPS), which takes into account wildcards,
 * and the DNSName/IPAddress subject alternative name PKIX extension.
 *
 * Returns: 1 for a successful match, and 0 on failure.
 **/
static int verify_hostname(X509* cert, const char *hostname)
{
    GENERAL_NAMES* subject_alt_names;
    int found_dns_name = 0;
    struct in_addr addr;
    int addr_len = 0;
    int cn_match = 0;

    if (!cert) {
        SPICE_DEBUG("warning: no cert!");
        return 0;
    }

    // only IpV4 supported
    if (inet_aton(hostname, &addr)) {
        addr_len = sizeof(struct in_addr);
    }

    /* try matching against:
     *  1) a DNS name as an alternative name (subjectAltName) extension
     *     in the certificate
     *  2) the common name (CN) in the certificate
     *
     *  either of these may be of the form: *.domain.tld
     *
     *  only try (2) if there is no subjectAltName extension of
     *  type dNSName
     */

    /* Check through all included subjectAltName extensions, comparing
     * against all those of type dNSName.
     */
    subject_alt_names = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);

    if (subject_alt_names) {
        int num_alts = sk_GENERAL_NAME_num(subject_alt_names);
        int i;
        for (i = 0; i < num_alts; i++) {
            const GENERAL_NAME* name = sk_GENERAL_NAME_value(subject_alt_names, i);
            if (name->type == GEN_DNS) {
                found_dns_name = 1;
                if (_gnutls_hostname_compare((char *)ASN1_STRING_data(name->d.dNSName),
                                             ASN1_STRING_length(name->d.dNSName),
                                             hostname)) {
                    SPICE_DEBUG("alt name match=%s", ASN1_STRING_data(name->d.dNSName));
                    GENERAL_NAMES_free(subject_alt_names);
                    return 1;
                }
            } else if (name->type == GEN_IPADD) {
                int alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
                found_dns_name = 1;
                if ((addr_len == alt_ip_len)&&
                    !memcmp(ASN1_STRING_data(name->d.iPAddress), &addr, addr_len)) {
                    SPICE_DEBUG("alt name IP match=%s",
                                inet_ntoa(*((struct in_addr*)ASN1_STRING_data(name->d.dNSName))));
                    GENERAL_NAMES_free(subject_alt_names);
                    return 1;
                }
            }
        }
        GENERAL_NAMES_free(subject_alt_names);
    }

    if (found_dns_name) {
        SPICE_DEBUG("warning: SubjectAltName mismatch");
        return 0;
    }

    /* extracting commonNames */
    X509_NAME* subject = X509_get_subject_name(cert);
    if (subject) {
        int pos = -1;
        X509_NAME_ENTRY* cn_entry;
        ASN1_STRING* cn_asn1;

        while ((pos = X509_NAME_get_index_by_NID(subject, NID_commonName, pos)) != -1) {
            cn_entry = X509_NAME_get_entry(subject, pos);
            if (!cn_entry) {
                continue;
            }
            cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry);
            if (!cn_asn1) {
                continue;
            }

            if (_gnutls_hostname_compare((char*)ASN1_STRING_data(cn_asn1),
                                         ASN1_STRING_length(cn_asn1),
                                         hostname)) {
                SPICE_DEBUG("common name match=%s", (char*)ASN1_STRING_data(cn_asn1));
                cn_match = 1;
                break;
            }
        }
    }

    if (!cn_match)
        SPICE_DEBUG("warning: common name mismatch");

    return cn_match;
}