Exemple #1
0
static VALUE
ossl_ocspbres_get_status(VALUE self)
{
    OCSP_BASICRESP *bs;
    OCSP_SINGLERESP *single;
    OCSP_CERTID *cid;
    ASN1_TIME *revtime, *thisupd, *nextupd;
    int status, reason;
    X509_EXTENSION *x509ext;
    VALUE ret, ary, ext;
    int count, ext_count, i, j;

    GetOCSPBasicRes(self, bs);
    ret = rb_ary_new();
    count = OCSP_resp_count(bs);
    for(i = 0; i < count; i++) {
        single = OCSP_resp_get0(bs, i);
        if(!single) continue;

        revtime = thisupd = nextupd = NULL;
        status = OCSP_single_get0_status(single, &reason, &revtime,
                                         &thisupd, &nextupd);
        if(status < 0) continue;
        if(!(cid = OCSP_CERTID_dup(single->certId)))
            ossl_raise(eOCSPError, NULL);
        ary = rb_ary_new();
        rb_ary_push(ary, ossl_ocspcertid_new(cid));
        rb_ary_push(ary, INT2NUM(status));
        rb_ary_push(ary, INT2NUM(reason));
        rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);
        rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);
        rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);
        ext = rb_ary_new();
        ext_count = OCSP_SINGLERESP_get_ext_count(single);
        for(j = 0; j < ext_count; j++) {
            x509ext = OCSP_SINGLERESP_get_ext(single, j);
            rb_ary_push(ext, ossl_x509ext_new(x509ext));
        }
        rb_ary_push(ary, ext);
        rb_ary_push(ret, ary);
    }

    return ret;
}
GTlsCertificateFlags
g_tls_database_openssl_verify_ocsp_response (GTlsDatabaseOpenssl *self,
                                             GTlsCertificate     *chain,
                                             OCSP_RESPONSE       *resp)
{
  GTlsCertificateFlags errors = 0;
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
  !defined(OPENSSL_NO_OCSP)
  GTlsDatabaseOpensslPrivate *priv;
  STACK_OF(X509) *chain_openssl = NULL;
  OCSP_BASICRESP *basic_resp = NULL;
  int ocsp_status = 0;
  int i;

  ocsp_status = OCSP_response_status (resp);
  if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
    {
      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
      goto end;
    }

  basic_resp = OCSP_response_get1_basic (resp);
  if (basic_resp == NULL)
    {
      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
      goto end;
    }

  chain_openssl = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
  priv = g_tls_database_openssl_get_instance_private (self);
  if ((chain_openssl == NULL) ||
      (priv->store == NULL))
    {
      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
      goto end;
    }

  if (OCSP_basic_verify (basic_resp, chain_openssl, priv->store, 0) <= 0)
    {
      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
      goto end;
    }

  for (i = 0; i < OCSP_resp_count (basic_resp); i++)
    {
      OCSP_SINGLERESP *single_resp = OCSP_resp_get0 (basic_resp, i);
      ASN1_GENERALIZEDTIME *revocation_time = NULL;
      ASN1_GENERALIZEDTIME *this_update_time = NULL;
      ASN1_GENERALIZEDTIME *next_update_time = NULL;
      int crl_reason = 0;
      int cert_status = 0;

      if (single_resp == NULL)
        continue;

      cert_status = OCSP_single_get0_status (single_resp,
                                             &crl_reason,
                                             &revocation_time,
                                             &this_update_time,
                                             &next_update_time);
      if (!OCSP_check_validity (this_update_time,
                                next_update_time,
                                300L,
                                -1L))
        {
          errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
          goto end;
        }

      switch (cert_status)
        {
        case V_OCSP_CERTSTATUS_GOOD:
          break;
        case V_OCSP_CERTSTATUS_REVOKED:
          errors = G_TLS_CERTIFICATE_REVOKED;
          goto end;
        case V_OCSP_CERTSTATUS_UNKNOWN:
          errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
          goto end;
        }
    }

end:
  if (basic_resp != NULL)
    OCSP_BASICRESP_free (basic_resp);

  if (resp != NULL)
    OCSP_RESPONSE_free (resp);

#endif
  return errors;
}
s2n_cert_validation_code s2n_x509_validator_validate_cert_stapled_ocsp_response(struct s2n_x509_validator *validator,
                                                                                struct s2n_connection *conn,
                                                                                const uint8_t *ocsp_response_raw,
                                                                                uint32_t ocsp_response_length) {

    if (validator->skip_cert_validation || !validator->check_stapled_ocsp) {
        return S2N_CERT_OK;
    }

#if !S2N_OCSP_STAPLING_SUPPORTED
    /* Default to safety */
    return S2N_CERT_ERR_UNTRUSTED;
#else

    OCSP_RESPONSE *ocsp_response = NULL;
    OCSP_BASICRESP *basic_response = NULL;

    s2n_cert_validation_code ret_val = S2N_CERT_ERR_INVALID;

    if (!ocsp_response_raw) {
        return ret_val;
    }

    ocsp_response = d2i_OCSP_RESPONSE(NULL, &ocsp_response_raw, ocsp_response_length);

    if (!ocsp_response) {
        goto clean_up;
    }

    int ocsp_status = OCSP_response_status(ocsp_response);

    if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
        goto clean_up;
    }

    basic_response = OCSP_response_get1_basic(ocsp_response);
    if (!basic_response) {
        goto clean_up;
    }

    int i;

    int certs_in_chain = sk_X509_num(validator->cert_chain);
    int certs_in_ocsp = sk_X509_num(OCSP_GET_CERTS(basic_response));

    if (certs_in_chain >= 2 && certs_in_ocsp >= 1) {
        X509 *responder = sk_X509_value(OCSP_GET_CERTS(basic_response), certs_in_ocsp - 1);

        /*check to see if one of the certs in the chain is an issuer of the cert in the ocsp response.*/
        /*if so it needs to be added to the OCSP verification chain.*/
        for (i = 0; i < certs_in_chain; i++) {
            X509 *issuer = sk_X509_value(validator->cert_chain, i);
            int issuer_value = X509_check_issued(issuer, responder);

            if (issuer_value == X509_V_OK) {
                if (!OCSP_basic_add1_cert(basic_response, issuer)) {
                    goto clean_up;
                }
            }
        }
    }

    int ocsp_verify_err = OCSP_basic_verify(basic_response, validator->cert_chain, validator->trust_store->trust_store, 0);
    /* do the crypto checks on the response.*/
    if (!ocsp_verify_err) {
        ret_val = S2N_CERT_ERR_EXPIRED;
        goto clean_up;
    }

    /* for each response check the timestamps and the status. */
    for (i = 0; i < OCSP_resp_count(basic_response); i++) {
        int status_reason;
        ASN1_GENERALIZEDTIME *revtime, *thisupd, *nextupd;

        OCSP_SINGLERESP *single_response = OCSP_resp_get0(basic_response, i);
        if (!single_response) {
            goto clean_up;
        }

        ocsp_status = OCSP_single_get0_status(single_response, &status_reason, &revtime,
                                              &thisupd, &nextupd);

        uint64_t this_update = 0;
        int thisupd_err = s2n_asn1_time_to_nano_since_epoch_ticks((const char *) thisupd->data,
                                                                  (uint32_t) thisupd->length, &this_update);

        uint64_t next_update = 0;
        int nextupd_err = s2n_asn1_time_to_nano_since_epoch_ticks((const char *) nextupd->data,
                                                                  (uint32_t) nextupd->length, &next_update);

        uint64_t current_time = 0;
        int current_time_err = conn->config->wall_clock(conn->config->sys_clock_ctx, &current_time);

        if (thisupd_err || nextupd_err || current_time_err) {
            ret_val = S2N_CERT_ERR_UNTRUSTED;
            goto clean_up;
        }

        if (current_time < this_update || current_time > next_update) {
            ret_val = S2N_CERT_ERR_EXPIRED;
            goto clean_up;
        }

        switch (ocsp_status) {
            case V_OCSP_CERTSTATUS_GOOD:
                break;

            case V_OCSP_CERTSTATUS_REVOKED:
                ret_val = S2N_CERT_ERR_REVOKED;
                goto clean_up;

            case V_OCSP_CERTSTATUS_UNKNOWN:
                goto clean_up;
            default:
                goto clean_up;
        }
    }

    ret_val = S2N_CERT_OK;

    clean_up:
    if (basic_response) {
        OCSP_BASICRESP_free(basic_response);
    }

    if (ocsp_response) {
        OCSP_RESPONSE_free(ocsp_response);
    }

    return ret_val;
#endif /* S2N_OCSP_STAPLING_SUPPORTED */
}