/* this is called during negotiationn */
int verify_callback(int ok, X509_STORE_CTX *ctx) {
    int err, depth;
    char buf[1024], *fingerprint;
    X509 *thecert;
    netsnmp_cert *cert;
    _netsnmp_verify_info *verify_info;
    SSL *ssl;

    thecert = X509_STORE_CTX_get_current_cert(ctx);
    err = X509_STORE_CTX_get_error(ctx);
    depth = X509_STORE_CTX_get_error_depth(ctx);
    
    /* things to do: */

    X509_NAME_oneline(X509_get_subject_name(thecert), buf, sizeof(buf));
    fingerprint = netsnmp_openssl_cert_get_fingerprint(thecert, -1);
    DEBUGMSGTL(("tls_x509:verify", "Cert: %s\n", buf));
    DEBUGMSGTL(("tls_x509:verify", "  fp: %s\n", fingerprint ?
                fingerprint : "unknown"));

    ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
    verify_info = SSL_get_ex_data(ssl, openssl_local_index);

    if (verify_info && ok && depth > 0) {
        /* remember that a parent certificate has been marked as trusted */
        verify_info->flags |= VRFY_PARENT_WAS_OK;
    }

    /* this ensures for self-signed certificates we have a valid
       locally known fingerprint and then accept it */
    if (!ok &&
        (X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT == err ||
         X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY == err ||
         X509_V_ERR_CERT_UNTRUSTED == err ||
         X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE == err ||
         X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN == err)) {

        cert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_FINGERPRINT,
                                 (void*)fingerprint);
        if (cert)
            DEBUGMSGTL(("tls_x509:verify", " Found locally: %s/%s\n",
                        cert->info.dir, cert->info.filename));


        if (cert) {
            DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err)));
            DEBUGMSGTL(("tls_x509:verify", "  accepting matching fp of self-signed certificate found in: %s\n",
                        cert->info.filename));
            SNMP_FREE(fingerprint);
            return 1;
        } else {
            DEBUGMSGTL(("tls_x509:verify", "  no matching fp found\n"));
            /* log where we are and why called */
            snmp_log(LOG_ERR, "tls verification failure: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err));
            SNMP_FREE(fingerprint);
            return 0;
        }

#if 0
        /*
         * This code is unreachable because of the return statements above.
         * Comment it out to avoid that Coverity complains about this code.
         */
        if (0 == depth && verify_info &&
            (verify_info->flags & VRFY_PARENT_WAS_OK)) {
            DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err)));
            DEBUGMSGTL(("tls_x509:verify", "  a parent was ok, so returning ok for this child certificate\n"));
            SNMP_FREE(fingerprint);
            return 1; /* we'll check the hostname later at this level */
        }
#endif
    }

    if (0 == ok)
        snmp_log(LOG_ERR, "tls verification failure: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err));
    else
        DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err)));
    DEBUGMSGTL(("tls_x509:verify", "  returning the passed in value of %d\n",
                ok));
    SNMP_FREE(fingerprint);
    return(ok);
}
Example #2
0
 * The only thing we make sure here is that any key change is not allowed. All
 * the rest of authentication happens separately *after* the initial
 * handshake, thus *after* this callback has returned successfully and TLS
 * session has been established.
 * @return 0 on error, 1 on success
 * @note This is an SSL callback, return type has to be int, not bool
 */
int TLSVerifyCallback(X509_STORE_CTX *store_ctx,
                      void *arg ARG_UNUSED)
{

    /* It's kind of tricky to get custom connection-specific info in this
     * callback. We first acquire a pointer to the SSL struct of the
     * connection and... */
    int ssl_idx = SSL_get_ex_data_X509_STORE_CTX_idx();
    SSL *ssl = X509_STORE_CTX_get_ex_data(store_ctx, ssl_idx);
    if (ssl == NULL)
    {
        UnexpectedError("No SSL context during handshake, denying!");
        return 0;
    }

    /* ...and then we ask for the custom data we attached there. */
    ConnectionInfo *conn_info = SSL_get_ex_data(ssl, CONNECTIONINFO_SSL_IDX);
    if (conn_info == NULL)
    {
        UnexpectedError("No conn_info at index %d", CONNECTIONINFO_SSL_IDX);
        return 0;
    }

    /* From that data get the key if the connection is already established. */
Example #3
0
//https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_verify.html
int VerifyPeer( int ok, X509_STORE_CTX* ctx )
{
	INFO("VERIFY PEER\n");
	char    buf[256];
    X509   *err_cert;
    int     err, depth;
    SSL    *ssl;
    SystemBase *sb;

    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() );
    sb = SSL_get_ex_data( ssl, 0 );

    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 (depth > mydata->verify_depth) {
        ok = 0;
        err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
        X509_STORE_CTX_set_error(ctx, err);
    } 
    if (!ok) {
        printf("verify error:num=%d:%s:depth=%d:%s\n", err,
                 X509_verify_cert_error_string(err), depth, buf);
    }
    */
    /*
    else if (mydata->verbose_mode)
		*/
    {
        printf("depth=%d:%s\n", depth, buf);
    }

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

    /*
    if (mydata->always_continue)
	{
      return 1;
	}
    else
	{
      return ok;
	}
	*/
	return 1;
}
Example #4
0
/* Call Backs */
int dtls_verify_cb(int ok, X509_STORE_CTX* store) {

    SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
    rtpp_stream *st = (rtpp_stream*)SSL_get_app_data(ssl);
    int depth = X509_STORE_CTX_get_error_depth(store);
    X509* cert = X509_STORE_CTX_get_current_cert(store);
    int override = 1;
    char buf[512];
    int err = X509_STORE_CTX_get_error(store);

    bzero(buf, 512);
    X509_NAME_oneline(X509_get_subject_name(cert),buf,sizeof(buf));
    rtpp_log_write(RTPP_LOG_INFO, glog, "depth[%d] subject = %s\n", depth, buf);
    bzero(buf, 512);
    X509_NAME_oneline(X509_get_issuer_name(cert),buf,sizeof(buf));
    rtpp_log_write(RTPP_LOG_INFO, glog, "depth[%d] issuer = %s\n", depth, buf);
    rtpp_log_write(RTPP_LOG_INFO, glog, "verify error:ok=%d num=%d:%s\n", ok,err, X509_verify_cert_error_string(err));  
    rtpp_log_write(RTPP_LOG_INFO, glog, "depth:%d, error code is %d\n", depth,store->error);

    switch (err)
    {
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
        rtpp_log_write(RTPP_LOG_INFO, glog, "issuer= %s\n",buf);
        break;

    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
    case X509_V_ERR_CERT_NOT_YET_VALID:
        rtpp_log_write(RTPP_LOG_INFO, glog, "notBefore\n");
        break;

    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
    case X509_V_ERR_CERT_HAS_EXPIRED:
        rtpp_log_write(RTPP_LOG_INFO, glog, "notAfter\n");
        break;

    case X509_V_ERR_CERT_SIGNATURE_FAILURE:
    case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
        rtpp_log_write(RTPP_LOG_INFO, glog, "unable to decrypt cert signature\n");
        break;

    case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
        rtpp_log_write(RTPP_LOG_INFO, glog, "Critical Extension\n");
        break;
    case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
        rtpp_log_write(RTPP_LOG_INFO, glog, "unable to decode issuer public key\n");
        break;

    case X509_V_ERR_OUT_OF_MEM:
        rtpp_log_write(RTPP_LOG_ERR, glog, "Out of memory \n");
        break;
    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
         if (st->remote_fp_algorithm && st->remote_fp_value)
         { 
            ok = 1;
            rtpp_log_write(RTPP_LOG_INFO, glog,"{%d}fingerprint verification st:%p fd:%d ssl:%p\n",depth, st, st->fd, ssl);
            if(!dtls_verify_digest(st,cert))
            {
                //override = 0;/* should be Zero*/
                ok = 0;
            }
                
        }
        rtpp_log_write(RTPP_LOG_INFO, glog, "Self signed certificate issue\n");
        break;
    case X509_V_ERR_CERT_REVOKED:
        rtpp_log_write(RTPP_LOG_INFO, glog, "certitifcate revoked\n");
        break;
    case X509_V_ERR_INVALID_CA:
        rtpp_log_write(RTPP_LOG_INFO, glog, "invalid CA\n");
        break;
    case X509_V_ERR_PATH_LENGTH_EXCEEDED:
        rtpp_log_write(RTPP_LOG_INFO, glog, "path length exceeded\n");
        break;
    case X509_V_ERR_INVALID_PURPOSE:
        rtpp_log_write(RTPP_LOG_INFO, glog, "invalid purpose\n");
        break;
    case X509_V_ERR_CERT_UNTRUSTED:
    case X509_V_ERR_CERT_REJECTED:
        rtpp_log_write(RTPP_LOG_INFO, glog, "certificate untrusted/rejected\n");
        break;
    default:
        rtpp_log_write(RTPP_LOG_INFO, glog, "default: error code is %d (check x509_vfy.h)\n", store->error);
        break;
    }
    if (!ok)
    {
        if (override)
        {
            rtpp_log_write(RTPP_LOG_INFO, glog, "something wrong with the cert[%d]!!! error code:%d (x509_vfy.h) Ignoring for Now\n",depth, store->error);
            ok=1;
        }
        else
            rtpp_log_write(RTPP_LOG_INFO, glog, "verify error:num=%d:%s depth:%d\n", err, X509_verify_cert_error_string(err),depth);  
    }
Example #5
0
int dane_verify_cb(int ok, X509_STORE_CTX *store) {
	struct ub_result *dns_result;
	struct ub_ctx* ctx;
	char dns_name[256];
	X509 *cert;
	SSL *con;
	typedef struct {
		int verbose_mode;
		int verify_depth;
		int always_continue;
	} mydata_t;
	int mydata_index;
	mydata_t *mydata;
	int retval, err, depth;
	
	if (b_err == NULL)
		b_err=BIO_new_fp(stderr,BIO_NOCLOSE);
	
	cert = X509_STORE_CTX_get_current_cert(store);
	err = X509_STORE_CTX_get_error(store);
	depth = X509_STORE_CTX_get_error_depth(ctx);
	
	int ssl_idx = SSL_get_ex_data_X509_STORE_CTX_idx();
	if (ssl_idx < 0) {
		BIO_printf(b_err, "DANE failed to find SSL index: %d\n", ssl_idx);
		return -1;
	}
	con = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
	mydata = SSL_get_ex_data(con, mydata_index);
	
	int peerfd;
	peerfd = SSL_get_fd(con);
	socklen_t len;
	struct sockaddr_storage addr;
	char ipstr[INET6_ADDRSTRLEN];
	char node[NI_MAXHOST];
	int port;

	len = sizeof addr;
	getpeername(peerfd, (struct sockaddr*)&addr, &len);

	// deal with both IPv4 and IPv6:
	if (addr.ss_family == AF_INET) {
	    struct sockaddr_in *s = (struct sockaddr_in *)&addr;
	    port = ntohs(s->sin_port);
	    inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
		struct sockaddr_in sa;
		sa.sin_family = AF_INET;
		inet_pton(AF_INET, ipstr, &sa.sin_addr);
		int res = getnameinfo((struct sockaddr*)&sa, sizeof(sa), node, sizeof(node), NULL, 0, 0);
	} else { // AF_INET6
		struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
	    port = ntohs(s->sin6_port);
	    inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
	}

	BIO_printf(b_err, "Peer IP address: %s\n", ipstr);
	BIO_printf(b_err, "Peer port      : %d\n", port);
	BIO_printf(b_err, "Peer hostname  : %s\n", node);
		
	ctx = ub_ctx_create();
	if(!ctx) {
		printf("error: could not create unbound context\n");
		return -1;
	}
	if( (retval=ub_ctx_resolvconf(ctx, "/etc/resolv.conf")) != 0) {
		printf("error reading resolv.conf: %s. errno says: %s\n", 
			ub_strerror(retval), strerror(errno));
		return -1;
	}
	if( (retval=ub_ctx_hosts(ctx, "/etc/hosts")) != 0) {
		printf("error reading hosts: %s. errno says: %s\n", 
			ub_strerror(retval), strerror(errno));
		return -1;
	}
	
	retval = sprintf(dns_name, "_%d._tcp.%s", port, node);
	if(retval < 0) {
		printf("failure to create dns name\n");
		return -1;
	}
	BIO_printf(b_err,"DANE dane_verify_cb() dns name: %s\n", dns_name);
	retval = ub_resolve(ctx, dns_name, 65534, 1, &dns_result);
	if(retval != 0) {
		BIO_printf(b_err, "resolve error: %s\n", ub_strerror(retval));
		return -1;
	}
	
	if(dns_result->havedata) {
		int i;
		for (i = 0; dns_result->data[i] != NULL; i++) {
			unsigned char usage, selector, matching_type;
			unsigned char *tlsa_bytes;
			
			if (dns_result->len[i] < 35) {
				// must have at least 1+1+1+32 bytes for the SHA-256 case
				BIO_printf(b_err, "DANE: Not enough data: %d available\n",
					dns_result->len[i]);
				return -1;
			}
			unsigned char *rdata = (unsigned char *)dns_result->data[i];
			usage = (char) *rdata++;
			selector = (char) *rdata++;
			matching_type = (char) *rdata++;
			tlsa_bytes = (unsigned char *) rdata;
			X509 *tlsa_cert;
			tlsa_cert = d2i_X509(NULL, &tlsa_bytes, dns_result->len[i]-3);
			
			BIO_printf(b_err, "DANE: Usage %d Selector %d Matching Type %d\n",
				usage, selector, matching_type);
			
			if (selector != 0)
				continue;
			if (matching_type != 0)
				continue;
			
			if (usage == 0 || usage == 2) {
				int retval;
				retval = ca_constraint(con, tlsa_cert, usage);
				if (retval == 0)
					BIO_printf(b_err, "DANE dane_verify_cb() Passed validation for usage %d\n", usage);
				else
					BIO_printf(b_err, "DANE dane_verify_cb() Failed validation for usage %d\n", usage);
				return retval;
			}
			if (usage == 1) {
				int retval;
				retval = service_cert_constraint(cert, tlsa_cert);
				if (retval == 0)
					BIO_printf(b_err, "DANE dane_verify_cb() Passed validation for usage %d\n", usage);
				else
					BIO_printf(b_err, "DANE dane_verify_cb() Failed validation for usage %d\n", usage);
				return retval;
			}
		}
	}
	return ok;
}
Example #6
0
/*
 *	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];
	EAP_HANDLER *handler = NULL;
	X509 *client_cert;
	SSL *ssl;
	int err, depth;
	EAP_TLS_CONF *conf;
	int my_ok = ok;

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

	if (!my_ok) {
		radlog(L_ERR,"--> verify error:num=%d:%s\n",err,
			X509_verify_cert_error_string(err));
		return my_ok;
	}

	/*
	 * 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);
	conf = (EAP_TLS_CONF *)SSL_get_ex_data(ssl, 1);

	/*
	 *	Get the Subject & Issuer
	 */
	subject[0] = issuer[0] = '\0';
	X509_NAME_oneline(X509_get_subject_name(client_cert), subject,
			  sizeof(subject));
	X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer,
			  sizeof(issuer));

	subject[sizeof(subject) - 1] = '\0';
	issuer[sizeof(issuer) - 1] = '\0';

	/*
	 *	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';

	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 {
				DEBUG2("    rlm_eap_tls: 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 */
	} /* depth == 0 */

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

		radlog(L_INFO, "--> User-Name = %s", handler->identity);
		radlog(L_INFO, "--> BUF-Name = %s", common_name);
		radlog(L_INFO, "--> subject = %s", subject);
		radlog(L_INFO, "--> issuer  = %s", issuer);
		radlog(L_INFO, "--> verify return:%d", my_ok);
	}
	return my_ok;
}