Exemplo n.º 1
0
bool Chain::checkIssued(Handle<Certificate> issuer, Handle<Certificate> cert){
	LOGGER_FN();

	try{
		int ret;

		X509 *iss = NULL;
		iss = issuer->internal();
		if (!iss){
			THROW_EXCEPTION(0, Chain, NULL, "iss");
		}
		X509 *sub = NULL;
		sub = cert->internal();
		if (!sub){
			THROW_EXCEPTION(0, Chain, NULL, "sub");
		}

		LOGGER_OPENSSL(X509_check_issued);
		ret = X509_check_issued(iss, sub);
		if (ret == X509_V_OK){
			return 1;
		}
		else{
			return 0;
		}
	}
	catch (Handle<Exception> e){
		THROW_EXCEPTION(0, Chain, e, "checkIssued");
	}	
}
Exemplo n.º 2
0
int
lws_x509_verify(struct lws_x509_cert *x509, struct lws_x509_cert *trusted,
		const char *common_name)
{
	char c[32], *p;
	int ret;

	if (common_name) {
		X509_NAME *xn = X509_get_subject_name(x509->cert);
		if (!xn)
			return -1;
		X509_NAME_oneline(xn, c, (int)sizeof(c) - 2);
		p = strstr(c, "/CN=");
		if (p)
			p = p + 4;
		else
			p = c;

		if (strcmp(p, common_name)) {
			lwsl_err("%s: common name mismatch\n", __func__);
			return -1;
		}
	}

	ret = X509_check_issued(trusted->cert, x509->cert);
	if (ret != X509_V_OK) {
		lwsl_err("%s: unable to verify cert relationship\n", __func__);
		lws_tls_err_describe();

		return -1;
	}

	return 0;
}
Exemplo n.º 3
0
int SslOcspStapling::getCertId(X509 *pCert)
{
    int     i, n;
    X509                *pXissuer;
    X509_STORE          *pXstore;
    STACK_OF(X509)      *pXchain;
    X509_STORE_CTX      *pXstore_ctx;


    pXchain = m_pCtx->extra_certs;
    n = sk_X509_num(pXchain);
    for (i = 0; i < n; i++)
    {
        pXissuer = sk_X509_value(pXchain, i);
        if (X509_check_issued(pXissuer, pCert) == X509_V_OK)
        {
            CRYPTO_add(&pXissuer->references, 1, CRYPTO_LOCK_X509);
            m_pCertId = OCSP_cert_to_id(NULL, pCert, pXissuer);
            X509_free(pXissuer);
            return 0;
        }
    }
    pXstore = SSL_CTX_get_cert_store(m_pCtx);
    if (pXstore == NULL)
    {
        setLastErrMsg("SSL_CTX_get_cert_store failed!\n");
        return LS_FAIL;
    }
    pXstore_ctx = X509_STORE_CTX_new();
    if (pXstore_ctx == NULL)
    {
        setLastErrMsg("X509_STORE_CTX_new failed!\n");
        return LS_FAIL;
    }
    if (X509_STORE_CTX_init(pXstore_ctx, pXstore, NULL, NULL) == 0)
    {
        setLastErrMsg("X509_STORE_CTX_init failed!\n");
        return LS_FAIL;
    }
    n = X509_STORE_CTX_get1_issuer(&pXissuer, pXstore_ctx, pCert);
    X509_STORE_CTX_free(pXstore_ctx);
    if ((n == -1) || (n == 0))
    {
        setLastErrMsg("X509_STORE_CTX_get1_issuer failed!\n");
        return LS_FAIL;
    }
    m_pCertId = OCSP_cert_to_id(NULL, pCert, pXissuer);
    X509_free(pXissuer);
    return 0;
}
Exemplo n.º 4
0
int modssl_verify_ocsp(X509_STORE_CTX *ctx, SSLSrvConfigRec *sc,
                       server_rec *s, conn_rec *c, apr_pool_t *pool)
{
    X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
    apr_pool_t *vpool;
    int rv;

    if (!cert) {
        /* starting with OpenSSL 1.0, X509_STORE_CTX_get_current_cert()
         * may yield NULL. Return early, but leave the ctx error as is. */
        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
                      "No cert available to check with OCSP");
        return 1;
    }
    else if (cert->valid && X509_check_issued(cert,cert) == X509_V_OK) {
        /* don't do OCSP checking for valid self-issued certs */
        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
                      "Skipping OCSP check for valid self-issued cert");
        X509_STORE_CTX_set_error(ctx, X509_V_OK);
        return 1;
    }

    /* Create a temporary pool to constrain memory use (the passed-in
     * pool may be e.g. a connection pool). */
    apr_pool_create(&vpool, pool);

    rv = verify_ocsp_status(cert, ctx, c, sc, s, vpool);

    apr_pool_destroy(vpool);

    /* Propagate the verification status back to the passed-in
     * context. */
    switch (rv) {
    case V_OCSP_CERTSTATUS_GOOD:
        X509_STORE_CTX_set_error(ctx, X509_V_OK);
        break;

    case V_OCSP_CERTSTATUS_REVOKED:
        X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
        break;

    case V_OCSP_CERTSTATUS_UNKNOWN:
        /* correct error code for application errors? */
        X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION);
        break;
    }

    return rv == V_OCSP_CERTSTATUS_GOOD;
}
Exemplo n.º 5
0
static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
					     SSL *ssl)
{
	/* OpenSSL has problems with certificate chains -- if there are
	   multiple certs with the same name, it doesn't necessarily
	   choose the _right_ one. (RT#1942)
	   Pick the right ones for ourselves and add them manually. */
	X509 *cert = SSL_get_certificate(ssl);
	X509 *cert2;
	X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
	X509_STORE_CTX ctx;

	if (!cert || !store)
		return;

	/* If we already have 'supporting' certs, don't add them again */
	if (vpninfo->https_ctx->extra_certs)
		return;

	if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
		return;

	while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
		char buf[200];
		if (cert2 == cert)
			break;
		if (X509_check_issued(cert2, cert2) == X509_V_OK)
			break;
		cert = cert2;
		X509_NAME_oneline(X509_get_subject_name(cert),
				  buf, sizeof(buf));
		vpn_progress(vpninfo, PRG_DEBUG,
			     _("Extra cert from cafile: '%s'\n"), buf);
		SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
	}
	X509_STORE_CTX_cleanup(&ctx);
}
Exemplo n.º 6
0
static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
{
	EVP_PKEY *pkey = NULL;
	X509 *cert = NULL;
	STACK_OF(X509) *ca;
	int ret = 0;
	char *pass;

	pass = vpninfo->cert_password;
	vpninfo->cert_password = NULL;
 retrypass:
	/* We do this every time round the loop, to work around a bug in
	   OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
	   when PKCS12_parse() returns an error, but *ca is left pointing
	   to the freed memory. */
	ca = NULL;
	if (!pass && request_passphrase(vpninfo, "openconnect_pkcs12", &pass,
					_("Enter PKCS#12 pass phrase:")) < 0) {
		PKCS12_free(p12);
		return -EINVAL;
	}
	if (!PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
		unsigned long err = ERR_peek_error();

		openconnect_report_ssl_errors(vpninfo);

		if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
		    ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
		    ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Parse PKCS#12 failed (wrong passphrase?)\n"));
			free(pass);
			pass = NULL;
			goto retrypass;
		}

		vpn_progress(vpninfo, PRG_ERR,
			     _("Parse PKCS#12 failed (see above errors)\n"));
		PKCS12_free(p12);
		free(pass);
		return -EINVAL;
	}
	free(pass);
	if (cert) {
		char buf[200];
		vpninfo->cert_x509 = cert;
		SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
		X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
		vpn_progress(vpninfo, PRG_INFO,
			     _("Using client certificate '%s'\n"), buf);
	} else {
		vpn_progress(vpninfo, PRG_ERR,
			     _("PKCS#12 contained no certificate!"));
		ret = -EINVAL;
	}

	if (pkey) {
		SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
		EVP_PKEY_free(pkey);
	} else {
		vpn_progress(vpninfo, PRG_ERR,
			     _("PKCS#12 contained no private key!"));
		ret = -EINVAL;
	}

	/* Only include supporting certificates which are actually necessary */
	if (ca) {
		int i;
	next:
		for (i = 0; i < sk_X509_num(ca); i++) {
			X509 *cert2 = sk_X509_value(ca, i);
			if (X509_check_issued(cert2, cert) == X509_V_OK) {
				char buf[200];

				if (cert2 == cert)
					break;
				if (X509_check_issued(cert2, cert2) == X509_V_OK)
					break;

				X509_NAME_oneline(X509_get_subject_name(cert2),
						  buf, sizeof(buf));
				vpn_progress(vpninfo, PRG_DEBUG,
					     _("Extra cert from PKCS#12: '%s'\n"), buf);
				CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
				SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
				cert = cert2;
				goto next;
			}
		}
		sk_X509_pop_free(ca, X509_free);
	}

	PKCS12_free(p12);
	return ret;
}
Exemplo n.º 7
0
static int
do_ca_cert_bootstrap(struct stream *stream)
{
    struct ssl_stream *sslv = ssl_stream_cast(stream);
    STACK_OF(X509) *chain;
    X509 *cert;
    FILE *file;
    int error;
    int fd;

    chain = SSL_get_peer_cert_chain(sslv->ssl);
    if (!chain || !sk_X509_num(chain)) {
        VLOG_ERR("could not bootstrap CA cert: no certificate presented by "
                 "peer");
        return EPROTO;
    }
    cert = sk_X509_value(chain, sk_X509_num(chain) - 1);

    /* Check that 'cert' is self-signed.  Otherwise it is not a CA
     * certificate and we should not attempt to use it as one. */
    error = X509_check_issued(cert, cert);
    if (error) {
        VLOG_ERR("could not bootstrap CA cert: obtained certificate is "
                 "not self-signed (%s)",
                 X509_verify_cert_error_string(error));
        if (sk_X509_num(chain) < 2) {
            VLOG_ERR("only one certificate was received, so probably the peer "
                     "is not configured to send its CA certificate");
        }
        return EPROTO;
    }

    fd = open(ca_cert.file_name, O_CREAT | O_EXCL | O_WRONLY, 0444);
    if (fd < 0) {
        if (errno == EEXIST) {
            VLOG_INFO_RL(&rl, "reading CA cert %s created by another process",
                         ca_cert.file_name);
            stream_ssl_set_ca_cert_file__(ca_cert.file_name, true, true);
            return EPROTO;
        } else {
            VLOG_ERR("could not bootstrap CA cert: creating %s failed: %s",
                     ca_cert.file_name, ovs_strerror(errno));
            return errno;
        }
    }

    file = fdopen(fd, "w");
    if (!file) {
        error = errno;
        VLOG_ERR("could not bootstrap CA cert: fdopen failed: %s",
                 ovs_strerror(error));
        unlink(ca_cert.file_name);
        return error;
    }

    if (!PEM_write_X509(file, cert)) {
        VLOG_ERR("could not bootstrap CA cert: PEM_write_X509 to %s failed: "
                 "%s", ca_cert.file_name,
                 ERR_error_string(ERR_get_error(), NULL));
        fclose(file);
        unlink(ca_cert.file_name);
        return EIO;
    }

    if (fclose(file)) {
        error = errno;
        VLOG_ERR("could not bootstrap CA cert: writing %s failed: %s",
                 ca_cert.file_name, ovs_strerror(error));
        unlink(ca_cert.file_name);
        return error;
    }

    VLOG_INFO("successfully bootstrapped CA cert to %s", ca_cert.file_name);
    log_ca_cert(ca_cert.file_name, cert);
    bootstrap_ca_cert = false;
    ca_cert.read = true;

    /* SSL_CTX_add_client_CA makes a copy of cert's relevant data. */
    SSL_CTX_add_client_CA(ctx, cert);

    SSL_CTX_set_cert_store(ctx, X509_STORE_new());
    if (SSL_CTX_load_verify_locations(ctx, ca_cert.file_name, NULL) != 1) {
        VLOG_ERR("SSL_CTX_load_verify_locations: %s",
                 ERR_error_string(ERR_get_error(), NULL));
        return EPROTO;
    }
    VLOG_INFO("killing successful connection to retry using CA cert");
    return EPROTO;
}
static ngx_int_t
ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)
{
    int                  i, n, rc;
    X509                *cert, *issuer;
    X509_STORE          *store;
    X509_STORE_CTX      *store_ctx;
    STACK_OF(X509)      *chain;
    ngx_ssl_stapling_t  *staple;

    staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
    cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);

#if OPENSSL_VERSION_NUMBER >= 0x10001000L
    SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);
#else
    chain = ssl->ctx->extra_certs;
#endif

    n = sk_X509_num(chain);

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
                   "SSL get issuer: %d extra certs", n);

    for (i = 0; i < n; i++) {
        issuer = sk_X509_value(chain, i);
        if (X509_check_issued(issuer, cert) == X509_V_OK) {
#if OPENSSL_VERSION_NUMBER >= 0x10100001L
            X509_up_ref(issuer);
#else
            CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509);
#endif

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
                           "SSL get issuer: found %p in extra certs", issuer);

            staple->cert = cert;
            staple->issuer = issuer;

            return NGX_OK;
        }
    }

    store = SSL_CTX_get_cert_store(ssl->ctx);
    if (store == NULL) {
        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                      "SSL_CTX_get_cert_store() failed");
        return NGX_ERROR;
    }

    store_ctx = X509_STORE_CTX_new();
    if (store_ctx == NULL) {
        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                      "X509_STORE_CTX_new() failed");
        return NGX_ERROR;
    }

    if (X509_STORE_CTX_init(store_ctx, store, NULL, NULL) == 0) {
        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                      "X509_STORE_CTX_init() failed");
        X509_STORE_CTX_free(store_ctx);
        return NGX_ERROR;
    }

    rc = X509_STORE_CTX_get1_issuer(&issuer, store_ctx, cert);

    if (rc == -1) {
        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                      "X509_STORE_CTX_get1_issuer() failed");
        X509_STORE_CTX_free(store_ctx);
        return NGX_ERROR;
    }

    if (rc == 0) {
        ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                      "\"ssl_stapling\" ignored, issuer certificate not found");
        X509_STORE_CTX_free(store_ctx);
        return NGX_DECLINED;
    }

    X509_STORE_CTX_free(store_ctx);

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
                   "SSL get issuer: found %p in cert store", issuer);

    staple->cert = cert;
    staple->issuer = issuer;

    return NGX_OK;
}
Exemplo n.º 9
0
/**
 * NOTE: From node.js
 *
 * Read a file that contains our certificate in "PEM" format,
 * possibly followed by a sequence of CA certificates that should be
 * sent to the peer in the Certificate message.
 *
 * Taken from OpenSSL - editted for style.
 */
int bud_context_use_certificate_chain(bud_context_t* ctx, BIO *in) {
  int ret;
  X509* x;
  X509* ca;
  X509_STORE* store;
  X509_STORE_CTX store_ctx;
  int r;
  unsigned long err;

  ERR_clear_error();

  ret = 0;
  x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);

  if (x == NULL) {
    SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
    goto end;
  }

  ret = SSL_CTX_use_certificate(ctx->ctx, x);
  ctx->cert = x;
  ctx->issuer = NULL;

  if (ERR_peek_error() != 0) {
    /* Key/certificate mismatch doesn't imply ret==0 ... */
    ret = 0;
  }

  if (ret) {
    /**
     * If we could set up our certificate, now proceed to
     * the CA certificates.
     */
    if (ctx->ctx->extra_certs != NULL) {
      sk_X509_pop_free(ctx->ctx->extra_certs, X509_free);
      ctx->ctx->extra_certs = NULL;
    }

    while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
      r = SSL_CTX_add_extra_chain_cert(ctx->ctx, ca);

      if (!r) {
        X509_free(ca);
        ret = 0;
        goto end;
      }
      /**
       * Note that we must not free r if it was successfully
       * added to the chain (while we must free the main
       * certificate, since its reference count is increased
       * by SSL_CTX_use_certificate).
       */

      /* Find issuer */
      if (ctx->issuer != NULL || X509_check_issued(ca, x) != X509_V_OK)
        continue;
      ctx->issuer = ca;
    }

    /* When the while loop ends, it's usually just EOF. */
    err = ERR_peek_last_error();
    if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
        ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
      ERR_clear_error();
    } else  {
      /* some real error */
      ret = 0;
    }
  }

end:
  if (ret) {
    /* Try getting issuer from cert store */
    if (ctx->issuer == NULL) {
      store = SSL_CTX_get_cert_store(ctx->ctx);
      ret = X509_STORE_CTX_init(&store_ctx, store, NULL, NULL);
      if (!ret)
        goto fatal;

      ret = X509_STORE_CTX_get1_issuer(&ctx->issuer, &store_ctx, ctx->cert);
      X509_STORE_CTX_cleanup(&store_ctx);

      ret = ret < 0 ? 0 : 1;
      /* NOTE: get_cert_store doesn't increment reference count */
    } else {
      /* Increment issuer reference count */
      CRYPTO_add(&ctx->issuer->references, 1, CRYPTO_LOCK_X509);
    }

    if (ctx->issuer != NULL) {
      /* Get ocsp_id */
      ctx->ocsp_id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
      if (ctx->ocsp_id == NULL) {
        ctx->issuer = NULL;
        goto fatal;
      }
    }
  } else {
    if (ctx->issuer != NULL)
      X509_free(ctx->issuer);
  }

fatal:
  if (ctx->cert != x && x != NULL)
    X509_free(x);

  return ret;
}
Exemplo n.º 10
0
bool CertificateIsSelfSigned(X509* cert) {
  bool self_signed = (X509_check_issued(cert, cert) == X509_V_OK);
  return self_signed;
}
Exemplo n.º 11
0
extern "C" int32_t CryptoNative_X509CheckIssued(X509* issuer, X509* subject)
{
    return X509_check_issued(issuer, subject);
}
Exemplo n.º 12
0
/**
 * NOTE: From node.js
 *
 * Read a file that contains our certificate in "PEM" format,
 * possibly followed by a sequence of CA certificates that should be
 * sent to the peer in the Certificate message.
 *
 * Taken from OpenSSL - editted for style.
 */
int bud_context_use_certificate_chain(bud_context_t* ctx, BIO *in) {
  int ret;
  X509* x;
  X509* ca;
  int r;
  unsigned long err;
  bud_context_pkey_type_t type;
  bud_context_pem_t* pem;

  ERR_clear_error();

  ret = 0;
  x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
  pem = NULL;

  if (x == NULL) {
    SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
    goto end;
  }

  ret = SSL_CTX_use_certificate(ctx->ctx, x);
  SSL_CTX_select_current_cert(ctx->ctx, x);
  type = bud_config_pkey_type(x->cert_info->key->pkey);

  pem = &ctx->pem[type];
  pem->cert = x;
  pem->issuer = NULL;

  if (ERR_peek_error() != 0) {
    /* Key/certificate mismatch doesn't imply ret==0 ... */
    ret = 0;
  }

  if (ret) {
    while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
      /*
       * Extra cert - add it to store to make OpenSSL pick and send proper
       * certs automatically
       */
      r = SSL_CTX_add1_chain_cert(ctx->ctx, ca);
      if (!r) {
        X509_free(ca);
        ret = 0;
        goto end;
      }

      /**
       * Note that we must not free r if it was successfully
       * added to the chain (while we must free the main
       * certificate, since its reference count is increased
       * by SSL_CTX_use_certificate).
       */

      /* Find issuer */
      if (pem->issuer != NULL || X509_check_issued(ca, x) != X509_V_OK)
        continue;
      pem->issuer = ca;
    }

    /* When the while loop ends, it's usually just EOF. */
    err = ERR_peek_last_error();
    if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
        ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
      ERR_clear_error();
    } else  {
      /* some real error */
      ret = 0;
    }
  }

end:
  if (ret) {
    /* Try getting issuer from cert store */
    if (pem->issuer == NULL) {
      X509_STORE* store;
      X509_STORE_CTX store_ctx;

      store = SSL_CTX_get_cert_store(ctx->ctx);
      ret = X509_STORE_CTX_init(&store_ctx, store, NULL, NULL);
      if (!ret)
        goto fatal;

      ret = X509_STORE_CTX_get1_issuer(&pem->issuer, &store_ctx, pem->cert);
      X509_STORE_CTX_cleanup(&store_ctx);

      ret = ret < 0 ? 0 : 1;
      /* NOTE: get_cert_store doesn't increment reference count */
    } else {
      /* Increment issuer reference count */
      CRYPTO_add(&pem->issuer->references, 1, CRYPTO_LOCK_X509);
    }

    if (pem->issuer != NULL) {
      /* Get ocsp_id */
      pem->ocsp_id = OCSP_cert_to_id(NULL, pem->cert, pem->issuer);
      if (pem->ocsp_id == NULL)
        goto fatal;
    }
  }

fatal:
  if (!ret && pem != NULL && pem->issuer != NULL) {
    X509_free(pem->issuer);
    pem->issuer = NULL;
  }

  if (!(pem != NULL && pem->cert == x) && x != NULL)
    X509_free(x);

  return ret;
}
Exemplo n.º 13
0
static int
do_ca_cert_bootstrap(struct vconn *vconn)
{
    struct ssl_vconn *sslv = ssl_vconn_cast(vconn);
    STACK_OF(X509) *chain;
    X509 *ca_cert;
    FILE *file;
    int error;
    int fd;

    chain = SSL_get_peer_cert_chain(sslv->ssl);
    if (!chain || !sk_X509_num(chain)) {
        VLOG_ERR("could not bootstrap CA cert: no certificate presented by "
                 "peer");
        return EPROTO;
    }
    ca_cert = sk_X509_value(chain, sk_X509_num(chain) - 1);

    /* Check that 'ca_cert' is self-signed.  Otherwise it is not a CA
     * certificate and we should not attempt to use it as one. */
    error = X509_check_issued(ca_cert, ca_cert);
    if (error) {
        VLOG_ERR("could not bootstrap CA cert: obtained certificate is "
                 "not self-signed (%s)",
                 X509_verify_cert_error_string(error));
        if (sk_X509_num(chain) < 2) {
            VLOG_ERR("only one certificate was received, so probably the peer "
                     "is not configured to send its CA certificate");
        }
        return EPROTO;
    }

    fd = open(ca_cert_file, O_CREAT | O_EXCL | O_WRONLY, 0444);
    if (fd < 0) {
        VLOG_ERR("could not bootstrap CA cert: creating %s failed: %s",
                 ca_cert_file, strerror(errno));
        return errno;
    }

    file = fdopen(fd, "w");
    if (!file) {
        int error = errno;
        VLOG_ERR("could not bootstrap CA cert: fdopen failed: %s",
                 strerror(error));
        unlink(ca_cert_file);
        return error;
    }

    if (!PEM_write_X509(file, ca_cert)) {
        VLOG_ERR("could not bootstrap CA cert: PEM_write_X509 to %s failed: "
                 "%s", ca_cert_file, ERR_error_string(ERR_get_error(), NULL));
        fclose(file);
        unlink(ca_cert_file);
        return EIO;
    }

    if (fclose(file)) {
        int error = errno;
        VLOG_ERR("could not bootstrap CA cert: writing %s failed: %s",
                 ca_cert_file, strerror(error));
        unlink(ca_cert_file);
        return error;
    }

    VLOG_INFO("successfully bootstrapped CA cert to %s", ca_cert_file);
    log_ca_cert(ca_cert_file, ca_cert);
    bootstrap_ca_cert = false;
    has_ca_cert = true;

    /* SSL_CTX_add_client_CA makes a copy of ca_cert's relevant data. */
    SSL_CTX_add_client_CA(ctx, ca_cert);

    /* SSL_CTX_use_certificate() takes ownership of the certificate passed in.
     * 'ca_cert' is owned by sslv->ssl, so we need to duplicate it. */
    ca_cert = X509_dup(ca_cert);
    if (!ca_cert) {
        out_of_memory();
    }
    if (SSL_CTX_load_verify_locations(ctx, ca_cert_file, NULL) != 1) {
        VLOG_ERR("SSL_CTX_load_verify_locations: %s",
                 ERR_error_string(ERR_get_error(), NULL));
        return EPROTO;
    }
    VLOG_INFO("killing successful connection to retry using CA cert");
    return EPROTO;
}
Exemplo n.º 14
0
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 */
}