From: Luke Howard Date: Thu, 17 Nov 2011 08:33:22 +0000 (+1100) Subject: Support EAP-TLS in Moonshot (requires OpenSSL) X-Git-Tag: tr-beta1~59 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=moonshot.git;a=commitdiff_plain;h=2ef42df0ecea8745a678fe26ff9b16072b93586b Support EAP-TLS in Moonshot (requires OpenSSL) --- diff --git a/moonshot/acinclude.m4 b/moonshot/acinclude.m4 index ff06090..401ad2a 100644 --- a/moonshot/acinclude.m4 +++ b/moonshot/acinclude.m4 @@ -115,7 +115,7 @@ else -DEAP_SERVER_GPSK \ -DEAP_SERVER_GPSK_SHA256 \ -DIEEE8021X_EAPOL"; - EAP_LIBS="-leap -lutils -lcrypto -ltls"; + EAP_LIBS="-leap -lutils -lcrypto -ltls -lssl"; EAP_LDFLAGS="-L$eapdir/eap_example -L$eapdir/src/utils -L$eapdir/src/crypto -L$eapdir/src/tls"; AC_SUBST(EAP_CFLAGS) AC_SUBST(EAP_LDFLAGS) @@ -249,6 +249,44 @@ fi fi ])dnl +AC_DEFUN([AX_CHECK_OPENSSL], +[AC_MSG_CHECKING(for OpenSSL) +OPENSSL_DIR= +found_openssl="no" +AC_ARG_WITH(openssl, + AC_HELP_STRING([--with-openssl], + [Use OpenSSL (in specified installation directory)]), + [check_openssl_dir="$withval"], + [check_openssl_dir=]) +for dir in $check_openssl_dir $prefix /usr /usr/local ; do + openssldir="$dir" + if test -f "$dir/include/openssl/opensslv.h"; then + found_openssl="yes"; + OPENSSL_DIR="${openssldir}" + OPENSSL_CFLAGS="-I$openssldir/include"; + break; + fi +done +AC_MSG_RESULT($found_openssl) +if test x_$found_openssl != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find OpenSSL libraries. + + Please install libssl or specify installation directory with + --with-openssl=(dir). +---------------------------------------------------------------------- +]) +else + printf "OpenSSL found in $openssldir\n"; + OPENSSL_LIBS="-lssl -lcrypto"; + OPENSSL_LDFLAGS="-L$openssldir/lib"; + AC_SUBST(OPENSSL_CFLAGS) + AC_SUBST(OPENSSL_LDFLAGS) + AC_SUBST(OPENSSL_LIBS) +fi +])dnl + AC_DEFUN([AX_CHECK_RADSEC], [AC_MSG_CHECKING(for radsec) RADSEC_DIR= diff --git a/moonshot/configure.ac b/moonshot/configure.ac index 4297345..1049dd7 100644 --- a/moonshot/configure.ac +++ b/moonshot/configure.ac @@ -81,6 +81,8 @@ if test x_$found_shibresolver = x_yes; then AX_CHECK_SHIBSP fi +AX_CHECK_OPENSSL + if test "x$acceptor" = "xyes" ; then AX_CHECK_RADSEC AX_CHECK_JANSSON diff --git a/moonshot/libeap b/moonshot/libeap index 3c68005..06ba9ae 160000 --- a/moonshot/libeap +++ b/moonshot/libeap @@ -1 +1 @@ -Subproject commit 3c6800594dbfcba5d36cfa5556288eae999f83ba +Subproject commit 06ba9ae7494306585ea8115619e98266ae4dc26c diff --git a/moonshot/mech_eap/Makefile.am b/moonshot/mech_eap/Makefile.am index 8c6f64c..a652182 100644 --- a/moonshot/mech_eap/Makefile.am +++ b/moonshot/mech_eap/Makefile.am @@ -42,13 +42,14 @@ mech_eap_la_CXXFLAGS += \ @TARGET_CFLAGS@ $(EAP_CFLAGS) mech_eap_la_LDFLAGS = -avoid-version -module \ -export-symbols $(GSSEAP_EXPORTS) -no-undefined \ - @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@ + @RADSEC_LDFLAGS@ @OPENSSL_LDFLAGS@ @TARGET_LDFLAGS@ if TARGET_WINDOWS mech_eap_la_LDFLAGS += -debug endif mech_eap_la_LIBADD = @KRB5_LIBS@ ../libeap/libeap.la @RADSEC_LIBS@ \ - @OPENSAML_LIBS@ @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@ + @OPENSAML_LIBS@ @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@ \ + @OPENSSL_LIBS@ mech_eap_la_SOURCES = \ acquire_cred.c \ acquire_cred_with_password.c \ diff --git a/moonshot/mech_eap/gssapiP_eap.h b/moonshot/mech_eap/gssapiP_eap.h index d1790a0..c763fbd 100644 --- a/moonshot/mech_eap/gssapiP_eap.h +++ b/moonshot/mech_eap/gssapiP_eap.h @@ -150,6 +150,7 @@ struct gss_name_struct #define CRED_FLAG_DEFAULT_CCACHE 0x00080000 #define CRED_FLAG_RESOLVED 0x00100000 #define CRED_FLAG_TARGET 0x00200000 +#define CRED_FLAG_CERTIFICATE 0x00400000 #define CRED_FLAG_PUBLIC_MASK 0x0000FFFF #ifdef HAVE_HEIMDAL_VERSION @@ -170,6 +171,8 @@ struct gss_cred_id_struct gss_buffer_desc caCertificate; gss_buffer_desc subjectNameConstraint; gss_buffer_desc subjectAltNameConstraint; + gss_buffer_desc clientCertificate; + gss_buffer_desc privateKey; #ifdef GSSEAP_ENABLE_REAUTH krb5_ccache krbCredCache; gss_cred_id_t reauthCred; diff --git a/moonshot/mech_eap/gssapi_eap.h b/moonshot/mech_eap/gssapi_eap.h index 588665b..02f132f 100644 --- a/moonshot/mech_eap/gssapi_eap.h +++ b/moonshot/mech_eap/gssapi_eap.h @@ -78,6 +78,13 @@ extern gss_OID GSS_EAP_CRED_SET_CRED_FLAG; extern gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD; /* + * Path to PKCS#12 private key file for use with EAP-TLS + * authentication. + */ +extern gss_OID GSS_EAP_CRED_SET_CRED_PRIVATE_KEY; + + +/* * Credentials flag indicating the local attributes * processing should be skipped. */ diff --git a/moonshot/mech_eap/init_sec_context.c b/moonshot/mech_eap/init_sec_context.c index e99b479..8a877fd 100644 --- a/moonshot/mech_eap/init_sec_context.c +++ b/moonshot/mech_eap/init_sec_context.c @@ -250,14 +250,22 @@ peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx) eapPeerConfig->anonymous_identity_len = 1 + realm.length; /* password */ - eapPeerConfig->password = (unsigned char *)cred->password.value; - eapPeerConfig->password_len = cred->password.length; + if ((cred->flags & CRED_FLAG_CERTIFICATE) == 0) { + eapPeerConfig->password = (unsigned char *)cred->password.value; + eapPeerConfig->password_len = cred->password.length; + } /* certs */ eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value; eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value; eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value; + if (cred->flags & CRED_FLAG_CERTIFICATE) { + eapPeerConfig->client_cert = (unsigned char *)cred->clientCertificate.value; + eapPeerConfig->private_key = (unsigned char *)cred->privateKey.value; + eapPeerConfig->private_key_passwd = (unsigned char *)cred->password.value; + } + *minor = 0; return GSS_S_COMPLETE; } diff --git a/moonshot/mech_eap/set_cred_option.c b/moonshot/mech_eap/set_cred_option.c index 7bb9b7b..98bb482 100644 --- a/moonshot/mech_eap/set_cred_option.c +++ b/moonshot/mech_eap/set_cred_option.c @@ -121,6 +121,15 @@ setCredPassword(OM_uint32 *minor, return gssEapSetCredPassword(minor, cred, buffer); } +static OM_uint32 +setCredPrivateKey(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + return gssEapSetCredClientCertificate(minor, cred, GSS_C_NO_BUFFER, buffer); +} + static struct { gss_OID_desc oid; OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred, @@ -146,12 +155,18 @@ static struct { { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x04" }, setCredPassword, }, + /* 1.3.6.1.4.1.5322.22.3.3.5 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x05" }, + setCredPrivateKey, + }, }; gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE = &setCredOps[0].oid; gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA = &setCredOps[1].oid; gss_OID GSS_EAP_CRED_SET_CRED_FLAG = &setCredOps[2].oid; gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD = &setCredOps[3].oid; +gss_OID GSS_EAP_CRED_SET_CRED_PRIVATE_KEY = &setCredOps[4].oid; OM_uint32 GSSAPI_CALLCONV gssspi_set_cred_option(OM_uint32 *minor, diff --git a/moonshot/mech_eap/util.h b/moonshot/mech_eap/util.h index 4f54d41..7a6c094 100644 --- a/moonshot/mech_eap/util.h +++ b/moonshot/mech_eap/util.h @@ -270,6 +270,12 @@ gssEapSetCredPassword(OM_uint32 *minor, const gss_buffer_t password); OM_uint32 +gssEapSetCredClientCertificate(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_buffer_t clientCert, + const gss_buffer_t privateKey); + +OM_uint32 gssEapSetCredService(OM_uint32 *minor, gss_cred_id_t cred, const gss_name_t target); diff --git a/moonshot/mech_eap/util_cred.c b/moonshot/mech_eap/util_cred.c index 746bd61..53a19a7 100644 --- a/moonshot/mech_eap/util_cred.c +++ b/moonshot/mech_eap/util_cred.c @@ -104,6 +104,8 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) gss_release_buffer(&tmpMinor, &cred->caCertificate); gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint); gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint); + gss_release_buffer(&tmpMinor, &cred->privateKey); + gss_release_buffer(&tmpMinor, &cred->clientCertificate); #ifdef GSSEAP_ENABLE_REAUTH if (cred->krbCredCache != NULL) { @@ -128,7 +130,8 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) static OM_uint32 readStaticIdentityFile(OM_uint32 *minor, gss_buffer_t defaultIdentity, - gss_buffer_t defaultPassword) + gss_buffer_t defaultPassword, + gss_buffer_t defaultPrivateKey) { OM_uint32 major, tmpMinor; FILE *fp = NULL; @@ -148,6 +151,11 @@ readStaticIdentityFile(OM_uint32 *minor, defaultPassword->value = NULL; } + if (defaultPrivateKey != GSS_C_NO_BUFFER) { + defaultPrivateKey->length = 0; + defaultPrivateKey->value = NULL; + } + ccacheName = getenv("GSSEAP_IDENTITY"); if (ccacheName == NULL) { #ifdef WIN32 @@ -203,6 +211,8 @@ readStaticIdentityFile(OM_uint32 *minor, dst = defaultIdentity; else if (i == 1) dst = defaultPassword; + else if (i == 2) + dst = defaultPrivateKey; else break; @@ -231,6 +241,7 @@ cleanup: if (GSS_ERROR(major)) { gss_release_buffer(&tmpMinor, defaultIdentity); zeroAndReleasePassword(defaultPassword); + gss_release_buffer(&tmpMinor, defaultPrivateKey); } memset(buf, 0, sizeof(buf)); @@ -371,7 +382,8 @@ staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor, *pName = GSS_C_NO_NAME; - major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER); + major = readStaticIdentityFile(minor, &defaultIdentity, + GSS_C_NO_BUFFER, GSS_C_NO_BUFFER); if (major == GSS_S_COMPLETE) { major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME, nameMech, pName); @@ -535,6 +547,68 @@ cleanup: return major; } +/* + * Currently only the privateKey path is exposed to the application + * (via gss_set_cred_option() or the third line in ~/.gss_eap_id). + * At some point in the future we may add support for setting the + * client certificate separately. + */ +OM_uint32 +gssEapSetCredClientCertificate(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_buffer_t clientCert, + const gss_buffer_t privateKey) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc newClientCert = GSS_C_EMPTY_BUFFER; + gss_buffer_desc newPrivateKey = GSS_C_EMPTY_BUFFER; + + if (cred->flags & CRED_FLAG_RESOLVED) { + major = GSS_S_FAILURE; + *minor = GSSEAP_CRED_RESOLVED; + goto cleanup; + } + + if (clientCert == GSS_C_NO_BUFFER && + privateKey == GSS_C_NO_BUFFER) { + cred->flags &= ~(CRED_FLAG_CERTIFICATE); + major = GSS_S_COMPLETE; + *minor = 0; + goto cleanup; + } + + if (clientCert != GSS_C_NO_BUFFER) { + major = duplicateBuffer(minor, clientCert, &newClientCert); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (privateKey != GSS_C_NO_BUFFER) { + major = duplicateBuffer(minor, privateKey, &newPrivateKey); + if (GSS_ERROR(major)) + goto cleanup; + } + + cred->flags |= CRED_FLAG_CERTIFICATE; + + gss_release_buffer(&tmpMinor, &cred->clientCertificate); + cred->clientCertificate = newClientCert; + + gss_release_buffer(&tmpMinor, &cred->privateKey); + cred->privateKey = newPrivateKey; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) { + gss_release_buffer(&tmpMinor, &newClientCert); + gss_release_buffer(&tmpMinor, &newPrivateKey); + } + + return major; +} + OM_uint32 gssEapSetCredService(OM_uint32 *minor, gss_cred_id_t cred, @@ -619,6 +693,8 @@ gssEapDuplicateCred(OM_uint32 *minor, duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint); if (src->subjectAltNameConstraint.value != NULL) duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint); + if (src->privateKey.value != NULL) + duplicateBufferOrCleanup(&src->privateKey, &dst->privateKey); #ifdef GSSEAP_ENABLE_REAUTH /* XXX krbCredCache, reauthCred */ @@ -643,9 +719,11 @@ staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred) gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER; gss_name_t defaultIdentityName = GSS_C_NO_NAME; gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER; + gss_buffer_desc defaultPrivateKey = GSS_C_EMPTY_BUFFER; int isDefaultIdentity = FALSE; - major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword); + major = readStaticIdentityFile(minor, &defaultIdentity, + &defaultPassword, &defaultPrivateKey); if (GSS_ERROR(major)) goto cleanup; @@ -673,17 +751,26 @@ staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred) } } - if (isDefaultIdentity && - (cred->flags & CRED_FLAG_PASSWORD) == 0) { - major = gssEapSetCredPassword(minor, cred, &defaultPassword); - if (GSS_ERROR(major)) - goto cleanup; + if (isDefaultIdentity) { + if (defaultPrivateKey.length != 0) { + major = gssEapSetCredClientCertificate(minor, cred, GSS_C_NO_BUFFER, + &defaultPrivateKey); + if (GSS_ERROR(major)) + goto cleanup; + } + + if ((cred->flags & CRED_FLAG_PASSWORD) == 0) { + major = gssEapSetCredPassword(minor, cred, &defaultPassword); + if (GSS_ERROR(major)) + goto cleanup; + } } cleanup: gssEapReleaseName(&tmpMinor, &defaultIdentityName); zeroAndReleasePassword(&defaultPassword); gss_release_buffer(&tmpMinor, &defaultIdentity); + gss_release_buffer(&tmpMinor, &defaultPrivateKey); return major; } @@ -734,7 +821,8 @@ gssEapResolveInitiatorCred(OM_uint32 *minor, goto cleanup; /* If we have a caller-supplied password, the credential is resolved. */ - if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) { + if ((resolvedCred->flags & + (CRED_FLAG_PASSWORD | CRED_FLAG_CERTIFICATE)) == 0) { major = GSS_S_CRED_UNAVAIL; *minor = GSSEAP_NO_DEFAULT_CRED; goto cleanup;