/* 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); }
* 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. */
//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; }
/* 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); }
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; }
/* * 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; }