示例#1
0
void
check_key_length (ssl_context *ssl)
{
  uint32_t key_bits;
  const x509_cert *certificate;
  const rsa_context *public_key;
  char buf[1024];

  certificate = ssl_get_peer_cert (ssl);
  if (NULL == certificate)
  {
    die ("Getting certificate failed");
  }

  x509parse_dn_gets(buf, 1024, &certificate->subject);
  verb_debug ("V: Certificate for subject '%s'", buf);

  public_key = &certificate->rsa;
  if (NULL == public_key)
  {
    die ("public key extraction failure");
  } else {
    verb_debug ("V: public key is ready for inspection");
  }
  key_bits = mpi_msb (&public_key->N);
  if (MIN_PUB_KEY_LEN >= key_bits)
  {
    die ("Unsafe public key size: %d bits", key_bits);
  } else {
    verb_debug ("V: key length appears safe");
  }
}
示例#2
0
uint32_t
dns_label_count(char *label, char *delim)
{
  char *label_tmp;
  char *saveptr;
  char *saveptr_tmp;
  uint32_t label_count;

  label_tmp = strdup(label);
  label_count = 0;
  saveptr = NULL;
  saveptr_tmp = NULL;
  saveptr = strtok_r(label_tmp, delim, &saveptr);
  if (NULL != saveptr)
  {
    // Did we find our first label?
    if (saveptr[0] != delim[0])
    {
      label_count++;
    }
    do
    {
      // Find all subsequent labels
      label_count++;
      saveptr_tmp = strtok_r(NULL, delim, &saveptr);
    } while (NULL != saveptr_tmp);
  }
  verb_debug ("V: label found; total label count: %d", label_count);
  free(label_tmp);
  return label_count;
}
示例#3
0
static int
read_http_date_from_bio(BIO *bio, uint32_t *result)
{
  int n;
  char buf[MAX_HTTP_HEADERS_SIZE];
  int buf_len=0;
  char *dateline, *endofline;

  while (buf_len < sizeof(buf)-1) {
    n = BIO_read(bio, buf+buf_len, sizeof(buf)-buf_len-1);
    if (n <= 0)
      return 0;
    buf_len += n;
    buf[buf_len] = 0;
    verb_debug ("V: read %d bytes.", n, buf);

    dateline = memmem(buf, buf_len, "\r\nDate: ", 8);
    if (NULL == dateline)
      continue;

    endofline = memmem(dateline+2, buf_len - (dateline-buf+2), "\r\n", 2);
    if (NULL == endofline)
      continue;

    *endofline = 0;
    return handle_date_line(dateline, result);
  }
  return -2;
}
示例#4
0
/* Run tlsdate and redirects stdout to the monitor_fd */
int
tlsdate (struct state *state)
{
  char **new_argv;
  pid_t pid;
  switch ((pid = fork()))
    {
    case 0: /* child! */
      break;
    case -1:
      perror ("fork() failed!");
      return -1;
    default:
      verb_debug ("[tlsdate-monitor] spawned tlsdate: %d", pid);
      state->tlsdate_pid = pid;
      return 0;
   }
  if (!(new_argv = build_argv (&state->opts)))
    fatal ("out of memory building argv");
  /* Replace stdout with the pipe back to tlsdated */
  if (dup2 (state->tlsdate_monitor_fd, STDOUT_FILENO) < 0)
    {
      perror ("dup2 failed");
      _exit (2);
    }
  execve (new_argv[0], new_argv, state->envp);
  perror ("execve() failed");
  _exit (1);
}
示例#5
0
void
check_key_length (SSL *ssl)
{
  uint32_t key_bits;
  X509 *certificate;
  EVP_PKEY *public_key;
  certificate = SSL_get_peer_certificate (ssl);
  if (NULL == certificate)
  {
    die ("Getting certificate failed");
  }
  public_key = X509_get_pubkey (certificate);
  if (NULL == public_key)
  {
    die ("public key extraction failure");
  } else {
    verb_debug ("V: public key is ready for inspection");
  }

  key_bits = get_certificate_keybits (public_key);
  if (MIN_PUB_KEY_LEN >= key_bits && public_key->type != EVP_PKEY_EC)
  {
    die ("Unsafe public key size: %d bits", key_bits);
  } else {
     if (public_key->type == EVP_PKEY_EC)
       if(key_bits >= MIN_ECC_PUB_KEY_LEN
          && key_bits <= MAX_ECC_PUB_KEY_LEN)
       {
         verb_debug ("V: ECC key length appears safe");
       } else {
         die ("Unsafe ECC key size: %d bits", key_bits);
     } else {
       verb_debug ("V: key length appears safe");
     }
  }
  EVP_PKEY_free (public_key);
}
示例#6
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");
  }

  if ((extcount = X509_get_ext_count(cert)) > 0)
  {
    int i;
    for (i = 0; i < extcount; ++i)
    {
      const char *extstr;
      X509_EXTENSION *ext;
      ext = X509_get_ext(cert, i);
      extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));

      if (!strcmp(extstr, "subjectAltName"))
      {

        int j;
        void *extvalstr;
        const unsigned char *tmp;

        STACK_OF(CONF_VALUE) *val;
        CONF_VALUE *nval;
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
        const
#endif
        X509V3_EXT_METHOD *method;

        if (!(method = X509V3_EXT_get(ext)))
        {
          break;
        }

        tmp = ext->value->data;
        if (method->it)
        {
          extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length,
                                    ASN1_ITEM_ptr(method->it));
        } else {
          extvalstr = method->d2i(NULL, &tmp, ext->value->length);
        }

        if (!extvalstr)
        {
          break;
        }

        if (method->i2v)
        {
          val = method->i2v(method, extvalstr, NULL);
          for (j = 0; j < sk_CONF_VALUE_num(val); ++j)
          {
            nval = sk_CONF_VALUE_value(val, j);
            if ((!strcasecmp(nval->name, "DNS") &&
                !strcasecmp(nval->value, hostname) ) ||
                (!strcasecmp(nval->name, "iPAddress") &&
                !strcasecmp(nval->value, hostname)))
            {
              verb ("V: subjectAltName matched: %s, type: %s", nval->value, nval->name); // We matched this; so it's safe to print
              ok = 1;
              break;
            }
            // Attempt to match subjectAltName DNS names
            if (!strcasecmp(nval->name, "DNS"))
            {
              ok = check_wildcard_match_rfc2595(hostname, nval->value);
              if (ok)
              {
                break;
              }
            }
            verb_debug ("V: subjectAltName found but not matched: %s, type: %s",
                nval->value, sanitize_string(nval->name));
          }
        }
      } else {
        verb_debug ("V: found non subjectAltName extension");
      }
      if (ok)
      {
        break;
      }
    }
  } else {
    verb_debug ("V: no X509_EXTENSION field(s) found");
  }
  X509_free(cert);
  return ok;
}
示例#7
0
// first we split strings on '.'
// then we call each split string a 'label'
// Do not allow '*' for the top level domain label; eg never allow *.*.com
// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
// Do allow *.example.com
uint32_t
check_wildcard_match_rfc2595 (const char *orig_hostname,
                      const char *orig_cert_wild_card)
{
  char *hostname;
  char *hostname_to_free;
  char *cert_wild_card;
  char *cert_wild_card_to_free;
  char *expected_label;
  char *wildcard_label;
  char *delim;
  char *wildchar;
  uint32_t ok;
  uint32_t wildcard_encountered;
  uint32_t label_count;

  // First we copy the original strings
  hostname = strndup(orig_hostname, strlen(orig_hostname));
  cert_wild_card = strndup(orig_cert_wild_card, strlen(orig_cert_wild_card));
  hostname_to_free = hostname;
  cert_wild_card_to_free = cert_wild_card;
  delim = strdup(".");
  wildchar = strdup("*");

  verb_debug ("V: Inspecting '%s' for possible wildcard match against '%s'",
         hostname, cert_wild_card);

  // By default we have not processed any labels
  label_count = dns_label_count(cert_wild_card, delim);

  // By default we have no match
  ok = 0;
  wildcard_encountered = 0;
  // First - do we have labels? If not, we refuse to even try to match
  if ((NULL != strpbrk(cert_wild_card, delim)) &&
      (NULL != strpbrk(hostname, delim)) &&
      (label_count <= ((uint32_t)RFC2595_MIN_LABEL_COUNT)))
  {
    if (wildchar[0] == cert_wild_card[0])
    {
      verb_debug ("V: Found wildcard in at start of provided certificate name");
      do
      {
        // Skip over the bytes between the first char and until the next label
        wildcard_label = strsep(&cert_wild_card, delim);
        expected_label = strsep(&hostname, delim);
        if (NULL != wildcard_label &&
            NULL != expected_label &&
            NULL != hostname &&
            NULL != cert_wild_card)
        {
          // Now we only consider this wildcard valid if the rest of the
          // hostnames match verbatim
          verb_debug ("V: Attempting match of '%s' against '%s'",
                 expected_label, wildcard_label);
          // This is the case where we have a label that begins with wildcard
          // Furthermore, we only allow this for the first label
          if (wildcard_label[0] == wildchar[0] &&
              0 == wildcard_encountered && 0 == ok)
          {
            verb ("V: Forced match of '%s' against '%s'", expected_label, wildcard_label);
            wildcard_encountered = 1;
          } else {
            verb_debug ("V: Attempting match of '%s' against '%s'",
                   hostname, cert_wild_card);
            if (0 == strcasecmp (expected_label, wildcard_label) &&
                label_count >= ((uint32_t)RFC2595_MIN_LABEL_COUNT))
            {
              ok = 1;
              verb_debug ("V: remaining labels match!");
              break;
            } else {
              ok = 0;
              verb_debug ("V: remaining labels do not match!");
              break;
            }
          }
        } else {
          // We hit this case when we have a mismatched number of labels
          verb_debug ("V: NULL label; no wildcard here");
          break;
        }
      } while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
    } else {
      verb_debug ("V: Not a RFC 2595 wildcard");
    }
  } else {
    verb_debug ("V: Not a valid wildcard certificate");
    ok = 0;
  }
  // Free our copies
  free(wildchar);
  free(delim);
  free(hostname_to_free);
  free(cert_wild_card_to_free);
  if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
  {
    verb_debug ("V: wildcard match of %s against %s",
          orig_hostname, orig_cert_wild_card);
    return (wildcard_encountered & ok);
  } else {
    verb_debug ("V: wildcard match failure of %s against %s",
          orig_hostname, orig_cert_wild_card);
    return 0;
  }
}
示例#8
0
/**
 * Run SSL handshake and store the resulting time value in the
 * 'time_map'.
 *
 * @param time_map where to store the current time
 * @param time_is_an_illusion
 * @param http whether to do an http request and take the date from that
 *     instead.
 */
static void
run_ssl (uint32_t *time_map, int time_is_an_illusion, int http)
{
  BIO *s_bio;
  SSL_CTX *ctx;
  SSL *ssl;
  struct stat statbuf;
  uint32_t result_time;

  SSL_load_error_strings();
  SSL_library_init();

  ctx = NULL;
  if (0 == strcmp("sslv23", protocol))
  {
    verb ("V: using SSLv23_client_method()");
    ctx = SSL_CTX_new(SSLv23_client_method());
  } else if (0 == strcmp("sslv3", protocol))
  {
    verb ("V: using SSLv3_client_method()");
    ctx = SSL_CTX_new(SSLv3_client_method());
  } else if (0 == strcmp("tlsv1", protocol))
  {
    verb ("V: using TLSv1_client_method()");
    ctx = SSL_CTX_new(TLSv1_client_method());
  } else
    die("Unsupported protocol `%s'", protocol);

  if (ctx == NULL)
    die("OpenSSL failed to support protocol `%s'", protocol);

  verb("V: Using OpenSSL for SSL");
  if (ca_racket)
  {
    if (-1 == stat(ca_cert_container, &statbuf))
    {
      die("Unable to stat CA certficate container %s", ca_cert_container);
    } else
    {
      switch (statbuf.st_mode & S_IFMT)
      {
      case S_IFREG:
        if (1 != SSL_CTX_load_verify_locations(ctx, ca_cert_container, NULL))
          fprintf(stderr, "SSL_CTX_load_verify_locations failed");
        break;
      case S_IFDIR:
        if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
          fprintf(stderr, "SSL_CTX_load_verify_locations failed");
        break;
      default:
        if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
        {
          fprintf(stderr, "SSL_CTX_load_verify_locations failed");
          die("Unable to load CA certficate container %s", ca_cert_container);
        }
      }
    }
  }

  if (NULL == (s_bio = make_ssl_bio(ctx)))
    die ("SSL BIO setup failed");
  BIO_get_ssl(s_bio, &ssl);
  if (NULL == ssl)
    die ("SSL setup failed");

  if (time_is_an_illusion)
  {
    SSL_set_info_callback(ssl, openssl_time_callback);
  }

  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
  verb("V: opening socket to %s:%s", host, port);
  if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
       (1 != BIO_set_conn_port(s_bio, port)) )
    die ("Failed to initialize connection to `%s:%s'", host, port);

  if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
    die ("BIO_new_fp returned error, possibly: %s", strerror(errno));

  // This should run in seccomp
  // eg:     prctl(PR_SET_SECCOMP, 1);
  if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later?
    die ("SSL connection failed");
  if (1 != BIO_do_handshake(s_bio))
    die ("SSL handshake failed");

  // from /usr/include/openssl/ssl3.h
  //  ssl->s3->server_random is an unsigned char of 32 bits
  memcpy(&result_time, ssl->s3->server_random, sizeof (uint32_t));
  verb("V: In TLS response, T=%lu", (unsigned long)ntohl(result_time));

  if (http) {
    char buf[1024];
    verb_debug ("V: Starting HTTP");
    if (snprintf(buf, sizeof(buf),
                 HTTP_REQUEST, HTTPS_USER_AGENT, hostname_to_verify) >= 1024)
      die("hostname too long");
    buf[1023]='\0'; /* Unneeded. */
    verb_debug ("V: Writing HTTP request");
    if (1 != write_all_to_bio(s_bio, buf))
      die ("write all to bio failed.");
    verb_debug ("V: Reading HTTP response");
    if (1 != read_http_date_from_bio(s_bio, &result_time))
      die ("read all from bio failed.");
    verb ("V: Received HTTP response. T=%lu", (unsigned long)result_time);

    result_time = htonl(result_time);
  }

  // Verify the peer certificate against the CA certs on the local system
  if (ca_racket) {
    inspect_key (ssl, hostname_to_verify);
  } else {
    verb ("V: Certificate verification skipped!");
  }
  check_key_length(ssl);

  memcpy(time_map, &result_time, sizeof (uint32_t));

  SSL_free(ssl);
  SSL_CTX_free(ctx);
}