Commit d4643d6e authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

openssl: fix cert check with non-DNS name fields present

Regression introduced in 5f5b6263 (released in 7.48.0)

Reported-by: Fabian Ruff
Fixes #875
parent b1839f6e
Loading
Loading
Loading
Loading
+20 −7
Original line number Original line Diff line number Diff line
@@ -1082,6 +1082,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
  struct in_addr addr;
  struct in_addr addr;
#endif
#endif
  CURLcode result = CURLE_OK;
  CURLcode result = CURLE_OK;
  bool dNSName = FALSE; /* if a dNSName field exists in the cert */


#ifdef ENABLE_IPV6
#ifdef ENABLE_IPV6
  if(conn->bits.ipv6_ip &&
  if(conn->bits.ipv6_ip &&
@@ -1102,16 +1103,23 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
  if(altnames) {
  if(altnames) {
    int numalts;
    int numalts;
    int i;
    int i;
    bool dnsmatched = FALSE;
    bool ipmatched = FALSE;


    /* get amount of alternatives, RFC2459 claims there MUST be at least
    /* get amount of alternatives, RFC2459 claims there MUST be at least
       one, but we don't depend on it... */
       one, but we don't depend on it... */
    numalts = sk_GENERAL_NAME_num(altnames);
    numalts = sk_GENERAL_NAME_num(altnames);


    /* loop through all alternatives while none has matched */
    /* loop through all alternatives - until a dnsmatch */
    for(i=0; (i<numalts) && !matched; i++) {
    for(i=0; (i < numalts) && !dnsmatched; i++) {
      /* get a handle to alternative name number i */
      /* get a handle to alternative name number i */
      const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
      const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);


      /* If a subjectAltName extension of type dNSName is present, that MUST
         be used as the identity. / RFC2818 section 3.1 */
      if(check->type == GEN_DNS)
        dNSName = TRUE;

      /* only check alternatives of the same type the target is */
      /* only check alternatives of the same type the target is */
      if(check->type == target) {
      if(check->type == target) {
        /* get data and length */
        /* get data and length */
@@ -1134,7 +1142,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
             /* if this isn't true, there was an embedded zero in the name
             /* if this isn't true, there was an embedded zero in the name
                string and we cannot match it. */
                string and we cannot match it. */
             Curl_cert_hostcheck(altptr, conn->host.name)) {
             Curl_cert_hostcheck(altptr, conn->host.name)) {
            matched = TRUE;
            dnsmatched = TRUE;
            infof(data,
            infof(data,
                  " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
                  " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
                  conn->host.dispname, altptr);
                  conn->host.dispname, altptr);
@@ -1145,7 +1153,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
          /* compare alternative IP address if the data chunk is the same size
          /* compare alternative IP address if the data chunk is the same size
             our server IP address is */
             our server IP address is */
          if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) {
          if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) {
            matched = TRUE;
            ipmatched = TRUE;
            infof(data,
            infof(data,
                  " subjectAltName: host \"%s\" matched cert's IP address!\n",
                  " subjectAltName: host \"%s\" matched cert's IP address!\n",
                  conn->host.dispname);
                  conn->host.dispname);
@@ -1155,14 +1163,19 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
      }
      }
    }
    }
    GENERAL_NAMES_free(altnames);
    GENERAL_NAMES_free(altnames);

    if(dnsmatched || (!dNSName && ipmatched)) {
      /* count as a match if the dnsname matched or if there was no dnsname
         fields at all AND there was an IP field match */
      matched = TRUE;
    }
  }
  }


  if(matched)
  if(matched)
    /* an alternative name matched */
    /* an alternative name matched */
    ;
    ;
  else if(altnames) {
  else if(dNSName) {
    /* an alternative name field existed, but didn't match and then we MUST
    /* an dNSName field existed, but didn't match and then we MUST fail */
       fail */
    infof(data, " subjectAltName does not match %s\n", conn->host.dispname);
    infof(data, " subjectAltName does not match %s\n", conn->host.dispname);
    failf(data, "SSL: no alternative certificate subject name matches "
    failf(data, "SSL: no alternative certificate subject name matches "
          "target host name '%s'", conn->host.dispname);
          "target host name '%s'", conn->host.dispname);