Implemented callback in libeap/src/crypto to allow mech_eap / ID Selector to ask...
[mech_eap.git] / mech_eap / init_sec_context.c
index a9d8891..de308b6 100644 (file)
@@ -39,6 +39,8 @@
 #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[] = {
@@ -201,6 +203,18 @@ peerNotifyPending(void *ctx GSSEAP_UNUSED)
 {
 }
 
+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,
@@ -211,6 +225,8 @@ static struct eapol_callbacks gssEapPolicyCallbacks = {
     peerSetConfigBlob,
     peerGetConfigBlob,
     peerNotifyPending,
+    NULL,  /* eap_param_needed */
+    peerNotifyCert
 };
 
 
@@ -356,6 +372,90 @@ peerProcessChbindResponse(void *context, int code, int nsid,
     } /* 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)
 {
@@ -464,6 +564,9 @@ 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;
 }
@@ -838,6 +941,8 @@ eapGssSmInitIdentity(OM_uint32 *minor,
                      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) {
@@ -854,11 +959,9 @@ eapGssSmInitIdentity(OM_uint32 *minor,
     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;
@@ -1368,3 +1471,4 @@ gss_init_sec_context(OM_uint32 *minor,
     gssEapTraceStatus( "gss_init_sec_context", major, *minor);
     return major;
 }
+