unsigned char client_random[SSL3_RANDOM_SIZE];
unsigned char server_random[SSL3_RANDOM_SIZE];
#endif
+
+ int (*validate_ca_cb)(int ok_so_far, X509* cert, void *ca_ctx);
+ void *validate_ca_ctx;
};
return context;
}
-
#ifdef CONFIG_NO_STDOUT_DEBUG
static void _tls_show_errors(void)
else if (depth == 2)
conn->peer_issuer_issuer = err_cert;
+ wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb(enter) - preverify_ok=%d "
+ "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+ preverify_ok, err, X509_verify_cert_error_string(err),
+ conn->ca_cert_verify, depth, buf);
+
+
context = conn->context;
match = conn->subject_match;
altmatch = conn->altsubject_match;
suffix_match = conn->suffix_match;
domain_match = conn->domain_match;
- if (!preverify_ok && !conn->ca_cert_verify)
- preverify_ok = 1;
- if (!preverify_ok && depth > 0 && conn->server_cert_only)
+ if (!preverify_ok && !conn->ca_cert_verify) {
+ if (conn->validate_ca_cb) {
+ preverify_ok = conn->validate_ca_cb(preverify_ok, err_cert, conn->validate_ca_ctx);
+ wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: validate_ca_cb returned %d", preverify_ok);
+ }
+ else {
+ preverify_ok = 1;
+ wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: allowing cert because !conn->ca_cert_verify\n");
+ }
+ }
+ if (!preverify_ok && depth > 0 && conn->server_cert_only) {
+ wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: allowing cert because depth > 0 && conn->server_cert_only\n");
preverify_ok = 1;
+ }
if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
(err == X509_V_ERR_CERT_HAS_EXPIRED ||
err == X509_V_ERR_CERT_NOT_YET_VALID)) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
+ wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Ignore certificate validity "
"time mismatch");
preverify_ok = 1;
}
struct wpabuf *cert;
cert = get_x509_cert(err_cert);
if (!cert) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
+ wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Could not fetch "
"server certificate data");
preverify_ok = 0;
} else {
* regardless of other problems.
*/
wpa_printf(MSG_DEBUG,
- "OpenSSL: Ignore validation issues for a pinned server certificate");
+ "tls_verify_cb: OpenSSL: Ignore validation issues for a pinned server certificate");
preverify_ok = 1;
}
wpabuf_free(cert);
#endif /* CONFIG_SHA256 */
if (!preverify_ok) {
- wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+ wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Certificate verification failed,"
" error %d (%s) depth %d for '%s'", err, err_str,
depth, buf);
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
return preverify_ok;
}
- wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
+ wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb(exit) - preverify_ok=%d "
"err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
preverify_ok, err, err_str,
conn->ca_cert_verify, depth, buf);
if (depth == 0 && match && os_strstr(buf, match) == NULL) {
- wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+ wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Subject '%s' did not "
"match with '%s'", buf, match);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
TLS_FAIL_SUBJECT_MISMATCH);
} else if (depth == 0 && altmatch &&
!tls_match_altsubject(err_cert, altmatch)) {
- wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+ wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: altSubjectName match "
"'%s' not found", altmatch);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
TLS_FAIL_ALTSUBJECT_MISMATCH);
} else if (depth == 0 && suffix_match &&
!tls_match_suffix(err_cert, suffix_match, 0)) {
- wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
+ wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Domain suffix match '%s' not found",
suffix_match);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
} else if (depth == 0 && domain_match &&
!tls_match_suffix(err_cert, domain_match, 1)) {
- wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+ wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Domain match '%s' not found",
domain_match);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
openssl_tls_cert_event(conn, err_cert, depth, buf);
if (conn->cert_probe && preverify_ok && depth == 0) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
+ wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Reject server certificate "
"on probe-only run");
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
static int tls_connection_ca_cert(struct tls_data *data,
- struct tls_connection *conn,
- const char *ca_cert, const u8 *ca_cert_blob,
- size_t ca_cert_blob_len, const char *ca_path)
+ struct tls_connection *conn,
+ const char *ca_cert, const u8 *ca_cert_blob,
+ size_t ca_cert_blob_len, const char *ca_path,
+ int (*validate_ca_cb)(int ok_so_far, X509* cert, void *ca_ctx),
+ void *validate_ca_ctx)
{
SSL_CTX *ssl_ctx = data->ssl;
X509_STORE *store;
if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
- "chain");
+ "chain; setting conn->ca_cert_verify=0");
conn->cert_probe = 1;
conn->ca_cert_verify = 0;
return 0;
} else {
/* No ca_cert configured - do not try to verify server
* certificate */
+ wpa_printf(MSG_DEBUG, "OpenSSL: tls_connection_ca_cert: No ca_cert; setting conn->ca_cert_verify=0");
conn->ca_cert_verify = 0;
+ conn->validate_ca_cb = validate_ca_cb;
+ conn->validate_ca_ctx = validate_ca_ctx;
}
return 0;
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
} else {
+ wpa_printf(MSG_DEBUG, "OpenSSL: tls_connection_set_verify: !verify_peer; setting conn->ca_cert_verify=0");
conn->ca_cert_verify = 0;
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
}
if (engine_id && ca_cert_id) {
if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
- } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
- params->ca_cert_blob,
- params->ca_cert_blob_len,
- params->ca_path))
- return -1;
+ } else {
+ if (tls_connection_ca_cert(data, conn, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path, params->validate_ca_cb,
+ params->validate_ca_ctx))
+ return -1;
+ }
if (engine_id && cert_id) {
if (tls_connection_engine_client_cert(conn, cert_id))
#include "radius/radius.h"
#include "util_radius.h"
#include "utils/radius_utils.h"
+#include "openssl/err.h"
+#include "libmoonshot.h"
/* methods allowed for phase1 authentication*/
static const struct eap_method_type allowed_eap_method_types[] = {
{
}
+static void peerNotifyCert(void *ctx GSSEAP_UNUSED,
+ int depth ,
+ const char *subject GSSEAP_UNUSED,
+ const char *altsubject[] GSSEAP_UNUSED,
+ int num_altsubject GSSEAP_UNUSED,
+ const char *cert_hash GSSEAP_UNUSED,
+ const struct wpabuf *cert GSSEAP_UNUSED)
+{
+ printf("peerNotifyCert: depth=%d; hash=%s (%p)\n", depth, cert_hash, cert_hash);
+}
+
+
static struct eapol_callbacks gssEapPolicyCallbacks = {
peerGetConfig,
peerGetBool,
peerSetConfigBlob,
peerGetConfigBlob,
peerNotifyPending,
+ NULL, /* eap_param_needed */
+ peerNotifyCert
};
} /* else log failures? */
}
+static int cert_to_byte_array(X509 *cert, unsigned char **bytes)
+{
+ unsigned char *buf;
+ unsigned char *p;
+
+ int len = i2d_X509(cert, NULL);
+ if (len <= 0) {
+ return -1;
+ }
+
+ p = buf = GSSEAP_MALLOC(len);
+ if (buf == NULL) {
+ return -1;
+ }
+
+ i2d_X509(cert, &buf);
+
+ *bytes = p;
+ return len;
+}
+
+static int sha256(unsigned char *bytes, int len, unsigned char *hash)
+{
+ EVP_MD_CTX ctx;
+ unsigned int hash_len;
+
+ EVP_MD_CTX_init(&ctx);
+ if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) {
+ printf("sha256(init_sec_context.c): EVP_DigestInit_ex failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ if (!EVP_DigestUpdate(&ctx, bytes, len)) {
+ printf("sha256(init_sec_context.c): EVP_DigestUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ if (!EVP_DigestFinal(&ctx, hash, &hash_len)) {
+ printf("sha256(init_sec_context.c): EVP_DigestFinal failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ return hash_len;
+}
+
+
+static int peerValidateCA(int ok_so_far, X509* cert, void *ca_ctx)
+{
+ const char *realm = NULL;
+ unsigned char *cert_bytes = NULL;
+ int cert_len;
+ unsigned char hash[32];
+ int hash_len;
+ MoonshotError *error = NULL;
+ struct eap_peer_config *eap_config = (struct eap_peer_config *) ca_ctx;
+ char *identity = strdup((const char *) eap_config->identity);
+ char* at = strchr(identity, '@');
+
+ if (at != NULL) {
+ *at = '\0';
+ }
+
+ cert_len = cert_to_byte_array(cert, &cert_bytes);
+ hash_len = sha256(cert_bytes, cert_len, hash);
+ GSSEAP_FREE(cert_bytes);
+
+ if (hash_len != 32) {
+ printf("peerValidateCA: Error: hash_len=%d, not 32!\n", hash_len);
+ return FALSE;
+ }
+
+ /* This is ugly, but it works -- anonymous_identity is '@' + realm
+ * (see peerConfigInit)
+ */
+ realm = ((char *) eap_config->anonymous_identity) + 1;
+
+ ok_so_far = moonshot_confirm_ca_certificate(identity, realm, hash, 32, &error);
+
+ printf("peerValidateCA: Returning %d\n", ok_so_far);
+ return ok_so_far;
+}
+
+
static OM_uint32
peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
{
eapPeerConfig->private_key_passwd = (char *)cred->password.value;
}
+ eapPeerConfig->validate_ca_cb = peerValidateCA;
+ eapPeerConfig->validate_ca_ctx = eapPeerConfig;
+
*minor = 0;
return GSS_S_COMPLETE;
}
OM_uint32 *smFlags)
{
struct eap_config eapConfig;
+ memset(&eapConfig, 0, sizeof(eapConfig));
+ eapConfig.cert_in_cb = 1;
#ifdef GSSEAP_ENABLE_REAUTH
if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) {
GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
GSSEAP_ASSERT(inputToken == GSS_C_NO_BUFFER);
- memset(&eapConfig, 0, sizeof(eapConfig));
-
ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
&gssEapPolicyCallbacks,
- ctx,
+ NULL, /* ctx?? */
&eapConfig);
if (ctx->initiatorCtx.eap == NULL) {
*minor = GSSEAP_PEER_SM_INIT_FAILURE;
gssEapTraceStatus( "gss_init_sec_context", major, *minor);
return major;
}
+