示例#1
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;
}
示例#2
0
int verify_callback(int ok, X509_STORE_CTX *ctx) 
{ 
char buf[256]; 
X509 *err_cert; 
int err,depth; 

err_cert=X509_STORE_CTX_get_current_cert(ctx); 
err = X509_STORE_CTX_get_error(ctx); 
depth = X509_STORE_CTX_get_error_depth(ctx); 

X509_NAME_oneline(X509_get_subject_name(err_cert),buf,256); 
BIO_printf(bio_err,"depth=%d %s\n",depth,buf); 
if (!ok) 
{ 
BIO_printf(bio_err,"verify error:num=%d:%s\n",err, 
X509_verify_cert_error_string(err)); 
if (depth < 6) 
{ 
ok=1; 
X509_STORE_CTX_set_error(ctx,X509_V_OK); 
} 
else 
{ 
ok=0; 
X509_STORE_CTX_set_error(ctx,X509_V_ERR_CERT_CHAIN_TOO_LONG); 
} 
} 
switch (ctx->error) 
{ 
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: 
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,256); 
BIO_printf(bio_err,"issuer= %s\n",buf); 
break; 
case X509_V_ERR_CERT_NOT_YET_VALID: 
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: 
BIO_printf(bio_err,"notBefore="); 
ASN1_UTCTIME_print(bio_err,X509_get_notBefore(ctx->current_cert)); 
BIO_printf(bio_err,"\n"); 
break; 
case X509_V_ERR_CERT_HAS_EXPIRED: 
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: 
BIO_printf(bio_err,"notAfter="); 
ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ctx->current_cert)); 
BIO_printf(bio_err,"\n"); 
break; 
} 
BIO_printf(bio_err,"verify return:%d\n",ok); 
return(ok); 
} 
示例#3
0
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
    printf("*** Verify callback function called\n");
	char    buf[256];
	X509   *err_cert;
	int     err, depth;
	SSL    *ssl;

	err_cert = X509_STORE_CTX_get_current_cert(ctx);
	err = X509_STORE_CTX_get_error(ctx);
	depth = X509_STORE_CTX_get_error_depth(ctx);

	/*
	 * Retrieve the pointer to the SSL of the connection currently treated
	 * and the application specific data stored into the SSL object.
	 */
	ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
	//mydata = SSL_get_ex_data(ssl, mydata_index);

	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);

	/*
	 * Catch a too long certificate chain. The depth limit set using
	 * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
	 * that whenever the "depth>verify_depth" condition is met, we
	 * have violated the limit and want to log this error condition.
	 * We must do it here, because the CHAIN_TOO_LONG error would not
	 * be found explicitly; only errors introduced by cutting off the
	 * additional certificates would be logged.
	 */
#if 0
	if (depth > mydata->verify_depth) {
		preverify_ok = 0;
		err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
		X509_STORE_CTX_set_error(ctx, err);
	}
#endif
	if (!preverify_ok) {
		printf("verify error:num=%d:%s:depth=%d:%s\n", err,
				X509_verify_cert_error_string(err), depth, buf);
	}

	printf("depth=%d:%s\n", depth, buf);

	/*
	 * At this point, err contains the last verification error. We can use
	 * it for something special
	 */
	if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
		X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
		printf("issuer= %s\n", buf);
	}

#if 0
	if (mydata->always_continue)
		return 1;
	else
#endif
		return preverify_ok;
}
示例#4
0
NOEXPORT int cert_check_local(X509_STORE_CTX *callback_ctx) {
    X509 *cert=X509_STORE_CTX_get_current_cert(callback_ctx);
    X509_OBJECT obj;
#if OPENSSL_VERSION_NUMBER>=0x10000000L
    STACK_OF(X509) *sk;
    int i;

    sk=X509_STORE_get1_certs(callback_ctx, X509_get_subject_name(cert));
    if(sk) {
        for(i=0; i<sk_X509_num(sk); i++)
            if(compare_pubkeys(cert, sk_X509_value(sk, i))) {
                sk_X509_pop_free(sk, X509_free);
                return 1; /* accept */
            }
        sk_X509_pop_free(sk, X509_free);
    }
#endif
    /* pre-1.0.0 API only returns a single matching certificate */
    if(X509_STORE_get_by_subject(callback_ctx, X509_LU_X509,
            X509_get_subject_name(cert), &obj)==1 &&
            compare_pubkeys(cert, obj.data.x509))
        return 1; /* accept */
    s_log(LOG_WARNING,
        "CERT: Certificate not found in local repository");
    X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_CERT_REJECTED);
    return 0; /* reject */
}
示例#5
0
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
  int ret = preverify_ok;

  /* determine the status for the current cert */
  X509_STORE_CTX_get_current_cert(ctx);
  int err = X509_STORE_CTX_get_error(ctx);
  int depth = X509_STORE_CTX_get_error_depth(ctx);

  /* conjure the stream & context to use */
  SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data
    (ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
  SSLSocket *stream =
    (SSLSocket*)SSL_get_ex_data(ssl, SSLSocket::GetSSLExDataIndex());

  /* if allow_self_signed is set, make sure that verification succeeds */
  if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT &&
      stream->getContext()["allow_self_signed"].toBoolean()) {
    ret = 1;
  }

  /* check the depth */
  Variant vdepth = stream->getContext()["verify_depth"];
  if (vdepth.toBoolean() && depth > vdepth.toInt64()) {
    ret = 0;
    X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
  }

  return ret;
}
示例#6
0
int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
{
    char    buf[CCERT_BUFSIZ];
    X509   *cert;
    int     err;
    int     depth;
    int     max_depth;
    SSL    *con;
    TLS_SESS_STATE *TLScontext;

    /* May be NULL as of OpenSSL 1.0, thanks for the API change! */
    cert = X509_STORE_CTX_get_current_cert(ctx);
    err = X509_STORE_CTX_get_error(ctx);
    con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
    TLScontext = SSL_get_ex_data(con, TLScontext_index);
    depth = X509_STORE_CTX_get_error_depth(ctx);

    /* Don't log the internal root CA unless there's an unexpected error. */
    if (ok && TLScontext->tadepth > 0 && depth > TLScontext->tadepth)
	return (1);

    /*
     * Certificate chain depth limit violations are mis-reported by the
     * OpenSSL library, from SSL_CTX_set_verify(3):
     * 
     * The certificate verification depth set with SSL[_CTX]_verify_depth()
     * stops the verification at a certain depth. The error message produced
     * will be that of an incomplete certificate chain and not
     * X509_V_ERR_CERT_CHAIN_TOO_LONG as may be expected.
     * 
     * We set a limit that is one higher than the user requested limit. If this
     * higher limit is reached, we raise an error even a trusted root CA is
     * present at this depth. This disambiguates trust chain truncation from
     * an incomplete trust chain.
     */
    max_depth = SSL_get_verify_depth(con) - 1;

    /*
     * We never terminate the SSL handshake in the verification callback,
     * rather we allow the TLS handshake to continue, but mark the session as
     * unverified. The application is responsible for closing any sessions
     * with unverified credentials.
     */
    if (max_depth >= 0 && depth > max_depth) {
	X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_CERT_CHAIN_TOO_LONG);
	ok = 0;
    }
    if (ok == 0)
	update_error_state(TLScontext, depth, cert, err);

    if (TLScontext->log_mask & TLS_LOG_VERBOSE) {
	if (cert)
	    X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
	else
	    strcpy(buf, "<unknown>");
	msg_info("%s: depth=%d verify=%d subject=%s",
		 TLScontext->namaddr, depth, ok, printable(buf, '?'));
    }
    return (1);
}
示例#7
0
int
server_verify_cert(X509_STORE_CTX *xs, void *ctx)
{
    log_debug("[X509] [VERIFY] hello !");
    X509_STORE_CTX_set_error(xs, X509_V_OK);
    return 1;
}
示例#8
0
/**
 * OpenSSL Certificate verification callback
 *
 * Called for each certificate in a chain being verified. OpenSSL
 * calls this in deepest first order from the certificate authority to
 * the peer certificate at position 0.
 *
 * Each certificate is stored in the fetch context the first time it
 * is presented. If an error is encountered it is only returned for
 * the peer certificate at position 0 allowing the enumeration of the
 * entire chain not stopping early at the depth of the erroring
 * certificate.
 *
 * \param verify_ok 0 if the caller has already determined the chain
 *                   has errors else 1
 * \param x509_ctx certificate context being verified
 * \return 1 to indicate verification should continue and 0 to indicate
 *          verification should stop.
 */
static int
fetch_curl_verify_callback(int verify_ok, X509_STORE_CTX *x509_ctx)
{
	int depth;
	struct curl_fetch_info *fetch;

	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
	fetch = X509_STORE_CTX_get_app_data(x509_ctx);

	/* record the max depth */
	if (depth > fetch->cert_depth) {
		fetch->cert_depth = depth;
	}

	/* certificate chain is excessively deep so fail verification */
	if (depth >= MAX_CERTS) {
		X509_STORE_CTX_set_error(x509_ctx,
					 X509_V_ERR_CERT_CHAIN_TOO_LONG);
		return 0;
	}

	/* save the certificate by incrementing the reference count and
	 * keeping a pointer.
	 */
	if (!fetch->cert_data[depth].cert) {
		fetch->cert_data[depth].cert = X509_STORE_CTX_get_current_cert(x509_ctx);
		fetch->cert_data[depth].cert->references++;
		fetch->cert_data[depth].err = X509_STORE_CTX_get_error(x509_ctx);
	}

	/* allow certificate chain to be completed */
	if (depth > 0) {
		verify_ok = 1;
	} else {
		/* search for deeper certificates in the chain with errors */
		for (depth = fetch->cert_depth; depth > 0; depth--) {
			if (fetch->cert_data[depth].err != 0) {
				/* error in previous certificate so fail verification */
				verify_ok = 0;
				X509_STORE_CTX_set_error(x509_ctx, fetch->cert_data[depth].err);
			}
		}
	}

	return verify_ok;
}
示例#9
0
static int verify_callback(int ok, X509_STORE_CTX *ctx)
{
	verify_context *vctx;
	X509 *err_cert;
	int err, depth;

	vctx = (verify_context *)ctx;

	err_cert = X509_STORE_CTX_get_current_cert(ctx);
	err = X509_STORE_CTX_get_error(ctx);
	depth = X509_STORE_CTX_get_error_depth(ctx);

	X509_NAME_oneline(X509_get_subject_name(err_cert), vctx->certdesc, sizeof(vctx->certdesc));

	if (!ok && depth >= 6)
	{
		X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
	}

	switch (ctx->error)
	{
	case X509_V_ERR_INVALID_PURPOSE:
	case X509_V_ERR_CERT_HAS_EXPIRED:
	case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
		err = X509_V_OK;
		X509_STORE_CTX_set_error(ctx, X509_V_OK);
		ok = 1;
		break;

	case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
		/*
			In this case, don't reset err to X509_V_OK, so that it can be reported,
			although we do return 1, so that the digest will still be checked
		*/
		ok = 1;
		break;

	default:
		break;
	}

	if (ok && vctx->err == X509_V_OK)
		vctx->err = err;
	return ok;
}
示例#10
0
文件: ossl.c 项目: Danylyuk/first_app
int
ossl_verify_cb(int ok, X509_STORE_CTX *ctx)
{
    VALUE proc, rctx, ret;
    struct ossl_verify_cb_args args;
    int state = 0;

    proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_verify_cb_idx);
    if ((void*)proc == 0)
	proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_verify_cb_idx);
    if ((void*)proc == 0)
	return ok;
    if (!NIL_P(proc)) {
	ret = Qfalse;
	rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new,
			  (VALUE)ctx, &state);
	if (state) {
	    rb_set_errinfo(Qnil);
	    rb_warn("StoreContext initialization failure");
	}
	else {
	    args.proc = proc;
	    args.preverify_ok = ok ? Qtrue : Qfalse;
	    args.store_ctx = rctx;
	    ret = rb_protect((VALUE(*)(VALUE))ossl_call_verify_cb_proc, (VALUE)&args, &state);
	    if (state) {
		rb_set_errinfo(Qnil);
		rb_warn("exception in verify_callback is ignored");
	    }
	    ossl_x509stctx_clear_ptr(rctx);
	}
	if (ret == Qtrue) {
	    X509_STORE_CTX_set_error(ctx, X509_V_OK);
	    ok = 1;
	}
	else{
	    if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) {
		X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
	    }
	    ok = 0;
	}
    }

    return ok;
}
示例#11
0
static VALUE
ossl_x509stctx_set_error(VALUE self, VALUE err)
{
    X509_STORE_CTX *ctx;

    GetX509StCtx(self, ctx);
    X509_STORE_CTX_set_error(ctx, NUM2INT(err));

    return err;
}
示例#12
0
文件: Ssl.c 项目: Nejuf/monit
static int _checkExpiration(T C, X509_STORE_CTX *ctx, X509 *certificate) {
        if (C->minimumValidDays) {
                // If we have warn-X-days-before-expire condition, check the certificate validity (already expired certificates are catched in preverify => we don't need to handle them here).
                int deltadays = 0;
#ifdef HAVE_ASN1_TIME_DIFF
                int deltaseconds;
                if (! ASN1_TIME_diff(&deltadays, &deltaseconds, NULL, X509_get_notAfter(certificate))) {
                        X509_STORE_CTX_set_error(ctx, X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
                        snprintf(C->error, sizeof(C->error), "invalid time format (in certificate's notAfter field)");
                        return 0;
                }
#else
                ASN1_GENERALIZEDTIME *t = ASN1_TIME_to_generalizedtime(X509_get_notAfter(certificate), NULL);
                if (! t) {
                        X509_STORE_CTX_set_error(ctx, X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
                        snprintf(C->error, sizeof(C->error), "invalid time format (in certificate's notAfter field)");
                        return 0;
                }
                TRY
                {
                        deltadays = (double)(Time_toTimestamp((const char *)t->data) - Time_now()) / 86400.;
                }
                ELSE
                {
                        X509_STORE_CTX_set_error(ctx, X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
                        snprintf(C->error, sizeof(C->error), "invalid time format (in certificate's notAfter field) -- %s", t->data);
                }
                FINALLY
                {
                        ASN1_STRING_free(t);
                }
                END_TRY;
#endif
                if (deltadays < C->minimumValidDays) {
                        X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION);
                        snprintf(C->error, sizeof(C->error), "certificate expire in %d days matches check limit [valid > %d days]", deltadays, C->minimumValidDays);
                        return 0;
                }
        }
示例#13
0
static int verify_cb(int ok, X509_STORE_CTX *ctx) {
    char *buf = NULL;
    X509 *err_cert;
    int err, depth;

    err_cert = X509_STORE_CTX_get_current_cert(ctx);
    err = X509_STORE_CTX_get_error(ctx);
    depth = X509_STORE_CTX_get_error_depth(ctx);

    if (depth > MAX_CERT_DEPTH) {
	ok = 0;
	err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
	X509_STORE_CTX_set_error(ctx, err);
    }

    if (!ok) {
	if (err_cert)
	    buf = X509_NAME_oneline(X509_get_subject_name(err_cert), NULL, 0);
	debug(DBG_WARN, "verify error: num=%d:%s:depth=%d:%s", err, X509_verify_cert_error_string(err), depth, buf ? buf : "");
	free(buf);
	buf = NULL;

	switch (err) {
	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
	    if (err_cert) {
		buf = X509_NAME_oneline(X509_get_issuer_name(err_cert), NULL, 0);
		if (buf) {
		    debug(DBG_WARN, "\tIssuer=%s", buf);
		    free(buf);
		    buf = NULL;
		}
	    }
	    break;
	case X509_V_ERR_CERT_NOT_YET_VALID:
	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
	    debug(DBG_WARN, "\tCertificate not yet valid");
	    break;
	case X509_V_ERR_CERT_HAS_EXPIRED:
	    debug(DBG_WARN, "Certificate has expired");
	    break;
	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
	    debug(DBG_WARN, "Certificate no longer valid (after notAfter)");
	    break;
	case X509_V_ERR_NO_EXPLICIT_POLICY:
	    debug(DBG_WARN, "No Explicit Certificate Policy");
	    break;
	}
    }
    return ok;
}
示例#14
0
文件: ossl.c 项目: genki/ruby
int 
ossl_verify_cb(int ok, X509_STORE_CTX *ctx)
{
    VALUE proc, rctx, ret;
    struct ossl_verify_cb_args args;
    int state = 0;

    proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_verify_cb_idx);
    if ((void*)proc == 0)
	proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_verify_cb_idx);
    if ((void*)proc == 0)
	return ok;
    if (!NIL_P(proc)) {
	rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new,
			  (VALUE)ctx, &state);
	ret = Qfalse;
	if (!state) {
	    args.proc = proc;
	    args.preverify_ok = ok ? Qtrue : Qfalse;
	    args.store_ctx = rctx;
	    ret = rb_ensure(ossl_call_verify_cb_proc, (VALUE)&args,
			    ossl_x509stctx_clear_ptr, rctx);
	}
	if (ret == Qtrue) {
	    X509_STORE_CTX_set_error(ctx, X509_V_OK);
	    ok = 1;
	}
	else{
	    if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) {
		X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
	    }
	    ok = 0;
	}
    }

    return ok;
}
示例#15
0
文件: openssl.c 项目: 1100101/inadyn
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
	char    buf[256];
	X509   *cert;
	int     err, depth;

	cert = X509_STORE_CTX_get_current_cert(ctx);
	err = X509_STORE_CTX_get_error(ctx);
	depth = X509_STORE_CTX_get_error_depth(ctx);

	X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));

	/*
	 * Catch a too long certificate chain. The depth limit set using
	 * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
	 * that whenever the "depth>verify_depth" condition is met, we
	 * have violated the limit and want to log this error condition.
	 * We must do it here, because the CHAIN_TOO_LONG error would not
	 * be found explicitly; only errors introduced by cutting off the
	 * additional certificates would be logged.
	 */
	if (depth > 100) {
		preverify_ok = 0;
		err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
		X509_STORE_CTX_set_error(ctx, err);
	}

	if (!preverify_ok)
		logit(LOG_ERR, "Certificate verification error:num=%d:%s:depth=%d:%s",
		      err, X509_verify_cert_error_string(err), depth, buf);

	/*
	 * At this point, err contains the last verification error. We can use
	 * it for something special
	 */
	if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
		X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
		logit(LOG_ERR, "issuer= %s", buf);
	}

	if (secure_ssl)
		return preverify_ok;

	return 1;
}
示例#16
0
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */
{
    void *stream;
    SSL *ssl;
    X509 *err_cert;
    int err, depth, ret;

    ret = preverify_ok;

    /* determine the status for the current cert */
    err_cert = X509_STORE_CTX_get_current_cert(ctx);
    err = X509_STORE_CTX_get_error(ctx);
    depth = X509_STORE_CTX_get_error_depth(ctx);

    /* conjure the stream & context to use */
    ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
    stream = SSL_get_ex_data(ssl, ssl_stream_data_index);

    /* if allow_self_signed is set, make sure that verification succeeds */
    if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GET_VER_OPT("allow_self_signed") && zval_is_true(*val)) {
        ret = 1;
    }

    /* check the depth */
    if (GET_VER_OPT("verify_depth")) {
        convert_to_long_ex(val);

        if (depth > Z_LVAL_PP(val)) {
            ret = 0;
            X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
        }
    }

    return ret;

}
示例#17
0
文件: context.c 项目: acasajus/pyGSI
/*
 * Globally defined verify callback
 *
 * Arguments: ok       - True everything is OK "so far", false otherwise
 *            x509_ctx - Contains the certificate being checked, the current
 *                       error number and depth, and the Connection we're
 *                       dealing with
 * Returns:   True if everything is okay, false otherwise
 */
static int global_verify_callback( int ok, X509_STORE_CTX * x509_ctx )
{
	PyObject *argv, *ret;

	SSL *ssl;

	ssl_ConnectionObj *conn;

	crypto_X509Obj *cert;

	X509 *x509;

	int errnum = X509_STORE_CTX_get_error(x509_ctx);

	int errdepth = X509_STORE_CTX_get_error_depth(x509_ctx);

#ifdef GSI_HANDSHAKE_DEBUG
	logMsg( 0, "GVC %d errnum %d errdepth", errnum, errdepth );
#endif

	ssl = (SSL *) X509_STORE_CTX_get_app_data(x509_ctx);
	conn = (ssl_ConnectionObj *) SSL_get_app_data(ssl);
	OBJ_END_THREADS( conn );
	Py_INCREF( conn );

	if ( conn->context->verify_callback != Py_None )
	{
		x509 = X509_STORE_CTX_get_current_cert(x509_ctx);

		cert = crypto_X509_New(x509, 0);
		argv = Py_BuildValue("(OOiii)", (PyObject *) conn, (PyObject *) cert,
				errnum, errdepth, ok);
		Py_DECREF(cert);
		/* We need to get back our thread state before calling the callback */
		ret = PyEval_CallObject(conn->context->verify_callback, argv);
		Py_DECREF(argv);

		if ( ret == NULL )
		{
			ok = 0;
		}
		else
		{
			if ( PyObject_IsTrue(ret) )
			{
				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
				ok = 1;
			}
			else
				ok = 0;

			Py_DECREF(ret);
		}
	}

	//Set the remove verification flag in the end
	if ( errdepth == 0 && ok )
	{
		conn->remoteCertVerified = 1;
	}

	Py_DECREF( conn );
	OBJ_BEGIN_THREADS( conn );

	return ok;
}
示例#18
0
static int verify_reject_cb(X509_STORE_CTX *ctx, void *arg) {
    X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION);
    return 0;
}
示例#19
0
文件: tls.c 项目: 23171580/libnetconf
/* based on the code of stunnel utility */
int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
	X509_STORE* store;
	X509_STORE_CTX store_ctx;
	X509_OBJECT obj;
	X509_NAME* subject;
	X509_NAME* issuer;
	X509* cert;
	X509_CRL* crl;
	X509_REVOKED* revoked;
	EVP_PKEY* pubkey;
	int i, n, rc;
	ASN1_TIME* next_update = NULL;

	if (!preverify_ok) {
		return 0;
	}

	if ((store = pthread_getspecific(tls_store_key)) == NULL) {
		ERROR("Failed to get thread-specific X509 store");
		return 1; /* fail */
	}

	cert = X509_STORE_CTX_get_current_cert(x509_ctx);
	subject = X509_get_subject_name(cert);
	issuer = X509_get_issuer_name(cert);

	/* try to retrieve a CRL corresponding to the _subject_ of
	 * the current certificate in order to verify it's integrity */
	memset((char *)&obj, 0, sizeof obj);
	X509_STORE_CTX_init(&store_ctx, store, NULL, NULL);
	rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
	X509_STORE_CTX_cleanup(&store_ctx);
	crl = obj.data.crl;
	if (rc > 0 && crl) {
		next_update = X509_CRL_get_nextUpdate(crl);

		/* verify the signature on this CRL */
		pubkey = X509_get_pubkey(cert);
		if (X509_CRL_verify(crl, pubkey) <= 0) {
			X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
			X509_OBJECT_free_contents(&obj);
			if (pubkey) {
				EVP_PKEY_free(pubkey);
			}
			return 0; /* fail */
		}
		if (pubkey) {
			EVP_PKEY_free(pubkey);
		}

		/* check date of CRL to make sure it's not expired */
		if (!next_update) {
			X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
			X509_OBJECT_free_contents(&obj);
			return 0; /* fail */
		}
		if (X509_cmp_current_time(next_update) < 0) {
			X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
			X509_OBJECT_free_contents(&obj);
			return 0; /* fail */
		}
		X509_OBJECT_free_contents(&obj);
	}

	/* try to retrieve a CRL corresponding to the _issuer_ of
	 * the current certificate in order to check for revocation */
	memset((char *)&obj, 0, sizeof obj);
	X509_STORE_CTX_init(&store_ctx, store, NULL, NULL);
	rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
	X509_STORE_CTX_cleanup(&store_ctx);
	crl = obj.data.crl;
	if (rc > 0 && crl) {
		/* check if the current certificate is revoked by this CRL */
		n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
		for (i = 0; i < n; i++) {
			revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
			if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) {
				ERROR("Certificate revoked");
				X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
				X509_OBJECT_free_contents(&obj);
				return 0; /* fail */
			}
		}
		X509_OBJECT_free_contents(&obj);
	}
	return 1; /* success */
}
/*
 *	Before trusting a certificate, you must make sure that the
 *	certificate is 'valid'. There are several steps that your
 *	application can take in determining if a certificate is
 *	valid. Commonly used steps are:
 *
 *	1.Verifying the certificate's signature, and verifying that
 *	the certificate has been issued by a trusted Certificate
 *	Authority.
 *
 *	2.Verifying that the certificate is valid for the present date
 *	(i.e. it is being presented within its validity dates).
 *
 *	3.Verifying that the certificate has not been revoked by its
 *	issuing Certificate Authority, by checking with respect to a
 *	Certificate Revocation List (CRL).
 *
 *	4.Verifying that the credentials presented by the certificate
 *	fulfill additional requirements specific to the application,
 *	such as with respect to access control lists or with respect
 *	to OCSP (Online Certificate Status Processing).
 *
 *	NOTE: This callback will be called multiple times based on the
 *	depth of the root certificate chain
 */
static int cbtls_verify(int ok, X509_STORE_CTX *ctx)
{
	char subject[1024]; /* Used for the subject name */
	char issuer[1024]; /* Used for the issuer name */
	char common_name[1024];
	char cn_str[1024];
	char buf[64];
	EAP_HANDLER *handler = NULL;
	X509 *client_cert;
	X509 *issuer_cert;
	SSL *ssl;
	int err, depth, lookup;
	EAP_TLS_CONF *conf;
	int my_ok = ok;
	REQUEST *request;
	ASN1_INTEGER *sn = NULL;
	ASN1_TIME *asn_time = NULL;
#ifdef HAVE_OPENSSL_OCSP_H
	X509_STORE *ocsp_store = NULL;
#endif

	client_cert = X509_STORE_CTX_get_current_cert(ctx);
	err = X509_STORE_CTX_get_error(ctx);
	depth = X509_STORE_CTX_get_error_depth(ctx);

	lookup = depth;

	/*
	 *	Log client/issuing cert.  If there's an error, log
	 *	issuing cert.
	 */
	if ((lookup > 1) && !my_ok) lookup = 1;

	/*
	 * Retrieve the pointer to the SSL of the connection currently treated
	 * and the application specific data stored into the SSL object.
	 */
	ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
	handler = (EAP_HANDLER *)SSL_get_ex_data(ssl, 0);
	request = handler->request;
	conf = (EAP_TLS_CONF *)SSL_get_ex_data(ssl, 1);
#ifdef HAVE_OPENSSL_OCSP_H
	ocsp_store = (X509_STORE *)SSL_get_ex_data(ssl, 2);
#endif


	/*
	 *	Get the Serial Number
	 */
	buf[0] = '\0';
	sn = X509_get_serialNumber(client_cert);

	/*
	 *	For this next bit, we create the attributes *only* if
	 *	we're at the client or issuing certificate.
	 */
	if ((lookup <= 1) && sn && (sn->length < (sizeof(buf) / 2))) {
		char *p = buf;
		int i;

		for (i = 0; i < sn->length; i++) {
			sprintf(p, "%02x", (unsigned int)sn->data[i]);
			p += 2;
		}
		pairadd(&handler->certs,
			pairmake(cert_attr_names[EAPTLS_SERIAL][lookup], buf, T_OP_SET));
	}


	/*
	 *	Get the Expiration Date
	 */
	buf[0] = '\0';
	asn_time = X509_get_notAfter(client_cert);
	if ((lookup <= 1) && asn_time && (asn_time->length < MAX_STRING_LEN)) {
		memcpy(buf, (char*) asn_time->data, asn_time->length);
		buf[asn_time->length] = '\0';
		pairadd(&handler->certs,
			pairmake(cert_attr_names[EAPTLS_EXPIRATION][lookup], buf, T_OP_SET));
	}

	/*
	 *	Get the Subject & Issuer
	 */
	subject[0] = issuer[0] = '\0';
	X509_NAME_oneline(X509_get_subject_name(client_cert), subject,
			  sizeof(subject));
	subject[sizeof(subject) - 1] = '\0';
	if ((lookup <= 1) && subject[0] && (strlen(subject) < MAX_STRING_LEN)) {
		pairadd(&handler->certs,
			pairmake(cert_attr_names[EAPTLS_SUBJECT][lookup], subject, T_OP_SET));
	}

	X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer,
			  sizeof(issuer));
	issuer[sizeof(issuer) - 1] = '\0';
	if ((lookup <= 1) && issuer[0] && (strlen(issuer) < MAX_STRING_LEN)) {
		pairadd(&handler->certs,
			pairmake(cert_attr_names[EAPTLS_ISSUER][lookup], issuer, T_OP_SET));
	}

	/*
	 *	Get the Common Name
	 */
	X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert),
				  NID_commonName, common_name, sizeof(common_name));
	common_name[sizeof(common_name) - 1] = '\0';
	if ((lookup <= 1) && common_name[0] && (strlen(common_name) < MAX_STRING_LEN)) {
		pairadd(&handler->certs,
			pairmake(cert_attr_names[EAPTLS_CN][lookup], common_name, T_OP_SET));
	}

	/*
	 *	If the CRL has expired, that might still be OK.
	 */
	if (!my_ok &&
	    (conf->allow_expired_crl) &&
	    (err == X509_V_ERR_CRL_HAS_EXPIRED)) {
		my_ok = 1;
		X509_STORE_CTX_set_error( ctx, 0 );
	}

	if (!my_ok) {
		const char *p = X509_verify_cert_error_string(err);
		radlog(L_ERR,"--> verify error:num=%d:%s\n",err, p);
		radius_pairmake(request, &request->packet->vps,
				"Module-Failure-Message", p, T_OP_SET);
		return my_ok;
	}

	switch (ctx->error) {

	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
		radlog(L_ERR, "issuer= %s\n", issuer);
		break;
	case X509_V_ERR_CERT_NOT_YET_VALID:
	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
		radlog(L_ERR, "notBefore=");
#if 0
		ASN1_TIME_print(bio_err, X509_get_notBefore(ctx->current_cert));
#endif
		break;
	case X509_V_ERR_CERT_HAS_EXPIRED:
	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
		radlog(L_ERR, "notAfter=");
#if 0
		ASN1_TIME_print(bio_err, X509_get_notAfter(ctx->current_cert));
#endif
		break;
	}

	/*
	 *	If we're at the actual client cert, apply additional
	 *	checks.
	 */
	if (depth == 0) {
		/*
		 *	If the conf tells us to, check cert issuer
		 *	against the specified value and fail
		 *	verification if they don't match.
		 */
		if (conf->check_cert_issuer &&
		    (strcmp(issuer, conf->check_cert_issuer) != 0)) {
			radlog(L_AUTH, "rlm_eap_tls: Certificate issuer (%s) does not match specified value (%s)!", issuer, conf->check_cert_issuer);
 			my_ok = 0;
 		}

		/*
		 *	If the conf tells us to, check the CN in the
		 *	cert against xlat'ed value, but only if the
		 *	previous checks passed.
		 */
		if (my_ok && conf->check_cert_cn) {
			if (!radius_xlat(cn_str, sizeof(cn_str), conf->check_cert_cn, handler->request, NULL)) {
				radlog(L_ERR, "rlm_eap_tls (%s): xlat failed.",
				       conf->check_cert_cn);
				/* if this fails, fail the verification */
				my_ok = 0;
			} else {
				RDEBUG2("checking certificate CN (%s) with xlat'ed value (%s)", common_name, cn_str);
				if (strcmp(cn_str, common_name) != 0) {
					radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) does not match specified value (%s)!", common_name, cn_str);
					my_ok = 0;
				}
			}
		} /* check_cert_cn */

#ifdef HAVE_OPENSSL_OCSP_H
		if (my_ok && conf->ocsp_enable){
			RDEBUG2("--> Starting OCSP Request");
			if(X509_STORE_CTX_get1_issuer(&issuer_cert, ctx, client_cert)!=1) {
				radlog(L_ERR, "Error: Couldn't get issuer_cert for %s", common_name);
			}
			my_ok = ocsp_check(ocsp_store, issuer_cert, client_cert, conf);
		}
#endif

		while (conf->verify_client_cert_cmd) {
			char filename[256];
			int fd;
			FILE *fp;

			snprintf(filename, sizeof(filename), "%s/%s.client.XXXXXXXX",
				 conf->verify_tmp_dir, progname);
			fd = mkstemp(filename);
			if (fd < 0) {
				RDEBUG("Failed creating file in %s: %s",
				       conf->verify_tmp_dir, strerror(errno));
				break;				       
			}

			fp = fdopen(fd, "w");
			if (!fp) {
				RDEBUG("Failed opening file %s: %s",
				       filename, strerror(errno));
				break;
			}

			if (!PEM_write_X509(fp, client_cert)) {
				fclose(fp);
				RDEBUG("Failed writing certificate to file");
				goto do_unlink;
			}
			fclose(fp);

			if (!radius_pairmake(request, &request->packet->vps,
					     "TLS-Client-Cert-Filename",
					     filename, T_OP_SET)) {
				RDEBUG("Failed creating TLS-Client-Cert-Filename");
				
				goto do_unlink;
			}

			RDEBUG("Verifying client certificate: %s",
			       conf->verify_client_cert_cmd);
			if (radius_exec_program(conf->verify_client_cert_cmd,
						request, 1, NULL, 0, 
						request->packet->vps,
						NULL, 1) != 0) {
				radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) fails external verification!", common_name);
				my_ok = 0;
			} else {
				RDEBUG("Client certificate CN %s passed external validation", common_name);
			}

		do_unlink:
			unlink(filename);
			break;
		}


	} /* depth == 0 */

	if (debug_flag > 0) {
		RDEBUG2("chain-depth=%d, ", depth);
		RDEBUG2("error=%d", err);

		RDEBUG2("--> User-Name = %s", handler->identity);
		RDEBUG2("--> BUF-Name = %s", common_name);
		RDEBUG2("--> subject = %s", subject);
		RDEBUG2("--> issuer  = %s", issuer);
		RDEBUG2("--> verify return:%d", my_ok);
	}
	return my_ok;
}
示例#21
0
// Certificate chain verification callback: return 1 if verified,
// 0 if remote cannot be verified (fail handshake).
//
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
  if (!preverify_ok || X509_STORE_CTX_get_error_depth(ctx) != 0)
    // already failed, or not at peer cert in chain
    return preverify_ok;

  X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
  SSL *ssn = (SSL *) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
  if (!ssn) {
    pn_transport_logf(NULL, "Error: unexpected error - SSL session info not available for peer verify!");
    return 0;  // fail connection
  }

  pn_transport_t *transport = (pn_transport_t *)SSL_get_ex_data(ssn, ssl_ex_data_index);
  if (!transport) {
    pn_transport_logf(NULL, "Error: unexpected error - SSL context info not available for peer verify!");
    return 0;  // fail connection
  }

  pni_ssl_t *ssl = transport->ssl;
  if (ssl->domain->verify_mode != PN_SSL_VERIFY_PEER_NAME) return preverify_ok;
  if (!ssl->peer_hostname) {
    pn_transport_logf(transport, "Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!");
    return 0;  // fail connection
  }

  ssl_log(transport, "Checking identifying name in peer cert against '%s'", ssl->peer_hostname);

  bool matched = false;

  /* first check any SubjectAltName entries, as per RFC2818 */
  GENERAL_NAMES *sans = (GENERAL_NAMES *) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
  if (sans) {
    int name_ct = sk_GENERAL_NAME_num( sans );
    int i;
    for (i = 0; !matched && i < name_ct; ++i) {
      GENERAL_NAME *name = sk_GENERAL_NAME_value( sans, i );
      if (name->type == GEN_DNS) {
        ASN1_STRING *asn1 = name->d.dNSName;
        if (asn1 && asn1->data && asn1->length) {
          unsigned char *str;
          int len = ASN1_STRING_to_UTF8( &str, asn1 );
          if (len >= 0) {
            ssl_log(transport, "SubjectAltName (dns) from peer cert = '%.*s'", len, str );
            matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len );
            OPENSSL_free( str );
          }
        }
      }
    }
    GENERAL_NAMES_free( sans );
  }

  /* if no general names match, try the CommonName from the subject */
  X509_NAME *name = X509_get_subject_name(cert);
  int i = -1;
  while (!matched && (i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) {
    X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i);
    ASN1_STRING *name_asn1 = X509_NAME_ENTRY_get_data(ne);
    if (name_asn1) {
      unsigned char *str;
      int len = ASN1_STRING_to_UTF8( &str, name_asn1);
      if (len >= 0) {
        ssl_log(transport, "commonName from peer cert = '%.*s'", len, str);
        matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len );
        OPENSSL_free(str);
      }
    }
  }

  if (!matched) {
    ssl_log(transport, "Error: no name matching %s found in peer cert - rejecting handshake.",
          ssl->peer_hostname);
    preverify_ok = 0;
#ifdef X509_V_ERR_APPLICATION_VERIFICATION
    X509_STORE_CTX_set_error( ctx, X509_V_ERR_APPLICATION_VERIFICATION );
#endif
  } else {
    ssl_log(transport, "Name from peer cert matched - peer is valid.");
  }
  return preverify_ok;
}
示例#22
0
NOEXPORT int ocsp_check(X509_STORE_CTX *callback_ctx) {
    SSL *ssl;
    CLI *c;
    X509 *cert;
    OCSP_CERTID *cert_id;
    STACK_OF(OPENSSL_STRING) *aia;
    int i, status=V_OCSP_CERTSTATUS_UNKNOWN;

    /* get the current certificate ID */
    cert=X509_STORE_CTX_get_current_cert(callback_ctx);
    if(!cert) {
        s_log(LOG_ERR, "OCSP: Failed to get the current certificate");
        X509_STORE_CTX_set_error(callback_ctx,
            X509_V_ERR_APPLICATION_VERIFICATION);
        return 0; /* reject */
    }
    if(!X509_NAME_cmp(X509_get_subject_name(cert),
            X509_get_issuer_name(cert))) {
        s_log(LOG_DEBUG, "OCSP: Ignoring root certificate");
        return 1; /* accept */
    }
    cert_id=OCSP_cert_to_id(NULL, cert, get_current_issuer(callback_ctx));
    if(!cert_id) {
        sslerror("OCSP: OCSP_cert_to_id");
        X509_STORE_CTX_set_error(callback_ctx,
            X509_V_ERR_APPLICATION_VERIFICATION);
        return 0; /* reject */
    }

    ssl=X509_STORE_CTX_get_ex_data(callback_ctx,
        SSL_get_ex_data_X509_STORE_CTX_idx());
    c=SSL_get_ex_data(ssl, cli_index);

    /* use the responder specified in the configuration file */
    if(c->opt->ocsp_url) {
        s_log(LOG_DEBUG, "OCSP: Connecting configured responder \"%s\"",
            c->opt->ocsp_url);
        if(ocsp_request(c, callback_ctx, cert_id, c->opt->ocsp_url)!=
                V_OCSP_CERTSTATUS_GOOD)
            return 0; /* reject */
    }

    /* use the responder from AIA (Authority Information Access) */
    if(!c->opt->option.aia)
        return 1; /* accept */
    aia=X509_get1_ocsp(cert);
    if(!aia)
        return 1; /* accept */
    for(i=0; i<sk_OPENSSL_STRING_num(aia); i++) {
        s_log(LOG_DEBUG, "OCSP: Connecting AIA responder \"%s\"",
            sk_OPENSSL_STRING_value(aia, i));
        status=ocsp_request(c, callback_ctx, cert_id,
            sk_OPENSSL_STRING_value(aia, i));
        if(status!=V_OCSP_CERTSTATUS_UNKNOWN)
            break; /* we received a definitive response */
    }
    X509_email_free(aia);
    if(status==V_OCSP_CERTSTATUS_GOOD)
        return 1; /* accept */
    return 0; /* reject */
}
示例#23
0
/* returns one of:
 * V_OCSP_CERTSTATUS_GOOD
 * V_OCSP_CERTSTATUS_REVOKED
 * V_OCSP_CERTSTATUS_UNKNOWN */
NOEXPORT int ocsp_request(CLI *c, X509_STORE_CTX *callback_ctx,
        OCSP_CERTID *cert_id, char *url) {
    int status=V_OCSP_CERTSTATUS_UNKNOWN;
    int reason;
    int ctx_err=X509_V_ERR_APPLICATION_VERIFICATION;
    OCSP_REQUEST *request=NULL;
    OCSP_RESPONSE *response=NULL;
    OCSP_BASICRESP *basic_response=NULL;
    ASN1_GENERALIZEDTIME *revoked_at=NULL,
        *this_update=NULL, *next_update=NULL;

    /* build request */
    request=OCSP_REQUEST_new();
    if(!request) {
        sslerror("OCSP: OCSP_REQUEST_new");
        goto cleanup;
    }
    if(!OCSP_request_add0_id(request, cert_id)) {
        sslerror("OCSP: OCSP_request_add0_id");
        goto cleanup;
    }
    OCSP_request_add1_nonce(request, NULL, -1);

    /* send the request and get a response */
    response=ocsp_get_response(c, request, url);
    if(!response)
        goto cleanup;
    status=OCSP_response_status(response);
    if(status!=OCSP_RESPONSE_STATUS_SUCCESSFUL) {
        s_log(LOG_WARNING, "OCSP: Responder error: %d: %s",
            status, OCSP_response_status_str(status));
        goto cleanup;
    }
    s_log(LOG_DEBUG, "OCSP: Response received");

    /* verify the response */
    basic_response=OCSP_response_get1_basic(response);
    if(!basic_response) {
        sslerror("OCSP: OCSP_response_get1_basic");
        goto cleanup;
    }
    if(OCSP_check_nonce(request, basic_response)<=0) {
        s_log(LOG_WARNING, "OCSP: Invalid nonce");
        goto cleanup;
    }
    if(OCSP_basic_verify(basic_response, NULL,
            c->opt->revocation_store, c->opt->ocsp_flags)<=0) {
        sslerror("OCSP: OCSP_basic_verify");
        goto cleanup;
    }
    if(!OCSP_resp_find_status(basic_response, cert_id, &status, &reason,
            &revoked_at, &this_update, &next_update)) {
        sslerror("OCSP: OCSP_resp_find_status");
        goto cleanup;
    }
    s_log(LOG_NOTICE, "OCSP: Status: %s", OCSP_cert_status_str(status));
    log_time(LOG_INFO, "OCSP: This update", this_update);
    log_time(LOG_INFO, "OCSP: Next update", next_update);
    /* check if the response is valid for at least one minute */
    if(!OCSP_check_validity(this_update, next_update, 60, -1)) {
        sslerror("OCSP: OCSP_check_validity");
        status=V_OCSP_CERTSTATUS_UNKNOWN;
        goto cleanup;
    }
    switch(status) {
    case V_OCSP_CERTSTATUS_GOOD:
        break;
    case V_OCSP_CERTSTATUS_REVOKED:
        if(reason==-1)
            s_log(LOG_WARNING, "OCSP: Certificate revoked");
        else
            s_log(LOG_WARNING, "OCSP: Certificate revoked: %d: %s",
                reason, OCSP_crl_reason_str(reason));
        log_time(LOG_NOTICE, "OCSP: Revoked at", revoked_at);
        ctx_err=X509_V_ERR_CERT_REVOKED;
        break;
    case V_OCSP_CERTSTATUS_UNKNOWN:
        s_log(LOG_WARNING, "OCSP: Unknown verification status");
    }
cleanup:
    if(request)
        OCSP_REQUEST_free(request);
    if(response)
        OCSP_RESPONSE_free(response);
    if(basic_response)
        OCSP_BASICRESP_free(basic_response);
    if(status!=V_OCSP_CERTSTATUS_GOOD)
        X509_STORE_CTX_set_error(callback_ctx, ctx_err);
    return status;
}
示例#24
0
int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
{
    char    buf[CCERT_BUFSIZ];
    X509   *cert;
    int     err;
    int     depth;
    SSL    *con;
    TLS_SESS_STATE *TLScontext;

    depth = X509_STORE_CTX_get_error_depth(ctx);
    cert = X509_STORE_CTX_get_current_cert(ctx);
    con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
    TLScontext = SSL_get_ex_data(con, TLScontext_index);

    /*
     * The callback function is called repeatedly, first with the root
     * certificate, and then with each intermediate certificate ending with
     * the peer certificate.
     * 
     * With each call, the validity of the current certificate (usage bits,
     * attributes, expiration, ... checked by the OpenSSL library) is
     * available in the "ok" argument. Error details are available via
     * X509_STORE_CTX API.
     * 
     * We never terminate the SSL handshake in the verification callback, rather
     * we allow the TLS handshake to continue, but mark the session as
     * unverified. The application is responsible for closing any sessions
     * with unverified credentials.
     * 
     * Certificate chain depth limit violations are mis-reported by the OpenSSL
     * library, from SSL_CTX_set_verify(3):
     * 
     * The certificate verification depth set with SSL[_CTX]_verify_depth()
     * stops the verification at a certain depth. The error message produced
     * will be that of an incomplete certificate chain and not
     * X509_V_ERR_CERT_CHAIN_TOO_LONG as may be expected.
     * 
     * We set a limit that is one higher than the user requested limit. If this
     * higher limit is reached, we raise an error even a trusted root CA is
     * present at this depth. This disambiguates trust chain truncation from
     * an incomplete trust chain.
     */
    if (depth >= SSL_get_verify_depth(con)) {
	ok = 0;
	X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
    }
    if (TLScontext->log_level >= 2) {
	X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
	acl_msg_info("%s: certificate verification depth=%d verify=%d subject=%s",
		 TLScontext->namaddr, depth, ok, printable(buf, '?'));
    }

    /*
     * If no errors, or we are not logging verification errors, we are done.
     */
    if (ok || (TLScontext->peer_status & TLS_CERT_FLAG_LOGGED) != 0)
	return (1);

    /*
     * One counter-example is enough.
     */
    TLScontext->peer_status |= TLS_CERT_FLAG_LOGGED;

#define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server")

    /*
     * Specific causes for verification failure.
     */
    switch (err = X509_STORE_CTX_get_error(ctx)) {
    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
	acl_msg_info("certificate verification failed for %s: "
		 "self-signed certificate", TLScontext->namaddr);
	break;
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:

	/*
	 * There is no difference between issuing cert not provided and
	 * provided, but not found in CAfile/CApath. Either way, we don't
	 * trust it.
	 */
	X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),
			  buf, sizeof(buf));
	acl_msg_info("certificate verification failed for %s: untrusted issuer %s",
		 TLScontext->namaddr, printable(buf, '?'));
	break;
    case X509_V_ERR_CERT_NOT_YET_VALID:
    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
	acl_msg_info("%s certificate verification failed for %s: certificate not"
		 " yet valid", PURPOSE, TLScontext->namaddr);
	break;
    case X509_V_ERR_CERT_HAS_EXPIRED:
    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
	acl_msg_info("%s certificate verification failed for %s: certificate has"
		 " expired", PURPOSE, TLScontext->namaddr);
	break;
    case X509_V_ERR_INVALID_PURPOSE:
	acl_msg_info("certificate verification failed for %s: not designated for "
		 "use as a %s certificate", TLScontext->namaddr, PURPOSE);
	break;
    case X509_V_ERR_CERT_CHAIN_TOO_LONG:
	acl_msg_info("certificate verification failed for %s: "
		 "certificate chain longer than limit(%d)",
		 TLScontext->namaddr, SSL_get_verify_depth(con) - 1);
	break;
    default:
	acl_msg_info("%s certificate verification failed for %s: num=%d:%s",
		 PURPOSE, TLScontext->namaddr, err,
		 X509_verify_cert_error_string(err));
	break;
    }

    return (1);
}
示例#25
0
static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
{
  sslctxparm * p = (sslctxparm *) arg;
  int ok, err;

  fprintf(stderr,"ssl_app_verify_callback sslctxparm=%p ctx=%p\n",
          (void *)p, (void*)ctx);

#if OPENSSL_VERSION_NUMBER<0x00907000L
/* not necessary in openssl 0.9.7 or later */

  fprintf(stderr,"This version %s of openssl does not support a parm (%p)"
          ", getting a global static %p \n",
          OPENSSL_VERSION_TEXT, (void *)p, (void *)globalparm);

  p = globalparm;
#endif

/* The following error should not occur. We test this to avoid segfault. */
  if (!p || !ctx) {
    fprintf(stderr,"Internal error in ssl_app_verify_callback "
            "sslctxparm=%p ctx=%p\n",(void *)p,(void*)ctx);
    return 0;
  }

  ok= X509_verify_cert(ctx);
  err=X509_STORE_CTX_get_error(ctx);

/* The following seems to be a problem in 0.9.7/8 openssl versions */

#if 1
  if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
      err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {
    fprintf(stderr,"X509_verify_cert: repairing self signed\n") ;
    X509_STORE_CTX_set_error(ctx,X509_V_OK);
    ok = 1;
  }
#endif

  if (ok && ctx->cert) {
    unsigned char * accessinfoURL ;

    accessinfoURL = my_get_ext(ctx->cert,p->accesstype ,NID_info_access);
    if (accessinfoURL) {

      if (strcmp((char *)p->accessinfoURL, (char *)accessinfoURL)) {
        fprintf(stderr, "Setting URL <%s>, was <%s>\n",
                (char *)accessinfoURL, (char *)p->accessinfoURL);
        OPENSSL_free(p->accessinfoURL);
        p->accessinfoURL = accessinfoURL;

        /* We need to be able to deal with a custom port number, but the
           URL in the cert uses a static one. We thus need to create a new
           URL that uses the currently requested port number which may not
           be the one this URL uses! */
        sprintf(newurl, "https://127.0.0.1:%d/509", portnum);
        fprintf(stderr, "But *really* Setting URL <%s>\n", newurl);

        curl_easy_setopt(p->curl, CURLOPT_URL, newurl);
      }
      else
        OPENSSL_free(accessinfoURL);
    }
  }
  return(ok);
}
示例#26
0
/* based on BSD-style licensed code of mod_ssl */
static int crl_check(CLI *c, X509_STORE_CTX *callback_ctx) {
    X509_STORE_CTX store_ctx;
    X509_OBJECT obj;
    X509_NAME *subject;
    X509_NAME *issuer;
    X509 *cert;
    X509_CRL *crl;
    X509_REVOKED *revoked;
    EVP_PKEY *pubkey;
    long serial;
    int i, n, rc;
    char *cp;
    ASN1_TIME *last_update=NULL, *next_update=NULL;

    /* determine certificate ingredients in advance */
    cert=X509_STORE_CTX_get_current_cert(callback_ctx);
    subject=X509_get_subject_name(cert);
    issuer=X509_get_issuer_name(cert);

    /* try to retrieve a CRL corresponding to the _subject_ of
     * the current certificate in order to verify it's integrity */
    memset((char *)&obj, 0, sizeof obj);
    X509_STORE_CTX_init(&store_ctx, c->opt->revocation_store, NULL, NULL);
    rc=X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
    X509_STORE_CTX_cleanup(&store_ctx);
    crl=obj.data.crl;
    if(rc>0 && crl) {
        cp=X509_NAME_oneline(subject, NULL, 0);
        s_log(LOG_INFO, "CRL: issuer: %s", cp);
        OPENSSL_free(cp);
        last_update=X509_CRL_get_lastUpdate(crl);
        next_update=X509_CRL_get_nextUpdate(crl);
        log_time(LOG_INFO, "CRL: last update", last_update);
        log_time(LOG_INFO, "CRL: next update", next_update);

        /* verify the signature on this CRL */
        pubkey=X509_get_pubkey(cert);
        if(X509_CRL_verify(crl, pubkey)<=0) {
            s_log(LOG_WARNING, "CRL: Invalid signature");
            X509_STORE_CTX_set_error(callback_ctx,
                X509_V_ERR_CRL_SIGNATURE_FAILURE);
            X509_OBJECT_free_contents(&obj);
            if(pubkey)
                EVP_PKEY_free(pubkey);
            return 0; /* reject connection */
        }
        if(pubkey)
            EVP_PKEY_free(pubkey);

        /* check date of CRL to make sure it's not expired */
        if(!next_update) {
            s_log(LOG_WARNING, "CRL: Invalid nextUpdate field");
            X509_STORE_CTX_set_error(callback_ctx,
                X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
            X509_OBJECT_free_contents(&obj);
            return 0; /* reject connection */
        }
        if(X509_cmp_current_time(next_update)<0) {
            s_log(LOG_WARNING, "CRL: CRL Expired - revoking all certificates");
            X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
            X509_OBJECT_free_contents(&obj);
            return 0; /* reject connection */
        }
        X509_OBJECT_free_contents(&obj);
    }

    /* try to retrieve a CRL corresponding to the _issuer_ of
     * the current certificate in order to check for revocation */
    memset((char *)&obj, 0, sizeof obj);
    X509_STORE_CTX_init(&store_ctx, c->opt->revocation_store, NULL, NULL);
    rc=X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
    X509_STORE_CTX_cleanup(&store_ctx);
    crl=obj.data.crl;
    if(rc>0 && crl) {
        /* check if the current certificate is revoked by this CRL */
        n=sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
        for(i=0; i<n; i++) {
            revoked=sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
            if(ASN1_INTEGER_cmp(revoked->serialNumber,
                    X509_get_serialNumber(cert)) == 0) {
                serial=ASN1_INTEGER_get(revoked->serialNumber);
                cp=X509_NAME_oneline(issuer, NULL, 0);
                s_log(LOG_WARNING, "CRL: Certificate with serial %ld (0x%lX) "
                    "revoked per CRL from issuer %s", serial, serial, cp);
                OPENSSL_free(cp);
                X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_CERT_REVOKED);
                X509_OBJECT_free_contents(&obj);
                return 0; /* reject connection */
            }
        }
        X509_OBJECT_free_contents(&obj);
    }
    return 1; /* accept connection */
}
示例#27
0
int CryptoManager::verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
	int err = X509_STORE_CTX_get_error(ctx);
	SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
	SSLVerifyData* verifyData = (SSLVerifyData*)SSL_get_ex_data(ssl, CryptoManager::idxVerifyData);

	// TODO: we should make sure that the trusted certificate store never overules KeyPrint, if present, because certificate pinning on an individual certificate is a stronger method of verification.

	// verifyData is unset only when KeyPrint has been pinned and we are not skipping errors due to incomplete chains
	// we can fail here f.ex. if the certificate has expired but is still pinned with KeyPrint
	if (!verifyData)
		return preverify_ok;

	bool allowUntrusted = verifyData->first;
	string keyp = verifyData->second;

	if (!keyp.empty()) {
		X509* cert = X509_STORE_CTX_get_current_cert(ctx);
		if (!cert)
			return 0;

		string kp2(keyp);
		if (kp2.compare(0, 12, "trusted_keyp") == 0) {
			// Possible follow up errors, after verification of a partial chain
			if (err == X509_V_ERR_CERT_UNTRUSTED || err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) {
				X509_STORE_CTX_set_error(ctx, X509_V_OK);
				return 1;
			}
		} else if (kp2.compare(0, 7, "SHA256/") != 0)
			return allowUntrusted ? 1 : 0;

		ByteVector kp = ssl::X509_digest(cert, EVP_sha256());
		ByteVector kp2v(kp.size());

		Encoder::fromBase32(&kp2[7], &kp2v[0], kp2v.size());
		if (std::equal(kp.begin(), kp.end(), kp2v.begin())) {
			// KeyPrint validated, we can get rid of it (to avoid unnecessary passes)
			SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, NULL);

			if (err != X509_V_OK) {
				// This is the right way to get the certificate store, although it is rather roundabout
				X509_STORE* store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(ssl));
				dcassert(store == ctx->ctx);

				// Hide the potential library error about trying to add a dupe
				ERR_set_mark();
				if (X509_STORE_add_cert(store, cert)) {
					X509_STORE_CTX_set_error(ctx, X509_V_OK);
					X509_verify_cert(ctx);
					err = X509_STORE_CTX_get_error(ctx);
				} else ERR_pop_to_mark();

				// KeyPrint was not root certificate or we don't have the issuer certificate, the best we can do is trust the pinned KeyPrint
				if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) {
					X509_STORE_CTX_set_error(ctx, X509_V_OK);
					// Set this to allow ignoring any follow up errors caused by the incomplete chain
					SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, &CryptoManager::trustedKeyprint);
					return 1;
				}
			}

			return (err == X509_V_OK) ? 1 : 0;
		} else {
			if (X509_STORE_CTX_get_error_depth(ctx) > 0)
				return 1;
		}
	}

	if (allowUntrusted) {
		/*
		// We let untrusted certificates through unconditionally, when allowed, but we like to complain
		if (!preverify_ok && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) {
			X509* cert = NULL;
			if ((cert = X509_STORE_CTX_get_current_cert(ctx)) != NULL) {
				X509_NAME* subject = X509_get_subject_name(cert);
				string tmp, line;

				tmp = getNameEntryByNID(subject, NID_commonName);
				if (!tmp.empty()) {
					CID certCID(tmp);
					if (certCID)
						tmp = Util::listToString(ClientManager::getInstance()->getNicks(certCID));
					line += (!line.empty() ? ", " : "") + tmp;
				}

				tmp = getNameEntryByNID(subject, NID_organizationName);
				if (!tmp.empty())
					line += (!line.empty() ? ", " : "") + tmp;

				ByteVector kp = ssl::X509_digest(cert, EVP_sha256());
				string keyp = "SHA256/" + Encoder::toBase32(&kp[0], kp.size());

				LogManager::getInstance()->message(STRING_F(VERIFY_CERT_FAILED, line % X509_verify_cert_error_string(err) % keyp), LogManager::LOG_INFO);
			}
		}*/

		return 1;
	}

	return preverify_ok;
}