From 7dbe76d4f41ac36f68d1d0299d55e685263f0b2f Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Thu, 2 Jun 2016 09:28:28 +0200 Subject: [PATCH] EAP-TLS method moved to standalone .h/.c file & some minor modifications --- EAPMethods/build/EAPTTLS.vcxproj | 2 + EAPMethods/build/EAPTTLS.vcxproj.filters | 6 + EAPMethods/build/EAPTTLSUI.vcxproj | 2 + EAPMethods/build/EAPTTLSUI.vcxproj.filters | 6 + EAPMethods/include/EAPMethods.h | Bin 130048 -> 121040 bytes EAPMethods/include/EAPTLS.h | 181 +++++++++++++++++++ EAPMethods/include/EAPTTLS.h | Bin 19886 -> 20162 bytes EAPMethods/include/StdAfx.h | Bin 2646 -> 2710 bytes EAPMethods/src/EAPMethods.cpp | Bin 70290 -> 55184 bytes EAPMethods/src/EAPTLS.cpp | 201 +++++++++++++++++++++ 10 files changed, 398 insertions(+) create mode 100644 EAPMethods/include/EAPTLS.h create mode 100644 EAPMethods/src/EAPTLS.cpp diff --git a/EAPMethods/build/EAPTTLS.vcxproj b/EAPMethods/build/EAPTTLS.vcxproj index 9128812..d52c307 100644 --- a/EAPMethods/build/EAPTTLS.vcxproj +++ b/EAPMethods/build/EAPTTLS.vcxproj @@ -81,6 +81,7 @@ + @@ -88,6 +89,7 @@ + diff --git a/EAPMethods/build/EAPTTLS.vcxproj.filters b/EAPMethods/build/EAPTTLS.vcxproj.filters index 4794cf5..ba6bfa7 100644 --- a/EAPMethods/build/EAPTTLS.vcxproj.filters +++ b/EAPMethods/build/EAPTTLS.vcxproj.filters @@ -33,6 +33,9 @@ Header Files + + Header Files + @@ -50,6 +53,9 @@ Source Files + + Source Files + diff --git a/EAPMethods/build/EAPTTLSUI.vcxproj b/EAPMethods/build/EAPTTLSUI.vcxproj index 59f50da..17a1eab 100644 --- a/EAPMethods/build/EAPTTLSUI.vcxproj +++ b/EAPMethods/build/EAPTTLSUI.vcxproj @@ -80,11 +80,13 @@ + + diff --git a/EAPMethods/build/EAPTTLSUI.vcxproj.filters b/EAPMethods/build/EAPTTLSUI.vcxproj.filters index bcacebb..812bb54 100644 --- a/EAPMethods/build/EAPTTLSUI.vcxproj.filters +++ b/EAPMethods/build/EAPTTLSUI.vcxproj.filters @@ -24,6 +24,9 @@ Header Files + + Header Files + @@ -41,6 +44,9 @@ Source Files + + Source Files + diff --git a/EAPMethods/include/EAPMethods.h b/EAPMethods/include/EAPMethods.h index 5b1859b427f392fd9e2d8d15ad4ea360e5d8abfb..920aaf57a55235861f90e38fd107e46a67334212 100644 GIT binary patch delta 474 zcmZqp!G2*Q`vy7A>3okE^)^>=#;}4}lOG5QOiy^t$hArEPUU1CFTTwMi+f^teHbzs ziWy266d3Xu(xw}pWYpfO!Z^tYP5ku(M*Znej2Js68z^xAH47;wF(d-@WiliKbrv(E zG88eCfqAJwo&wOk{K^VidXp8qwI}Ow@l3C%WwhCTz?d*hLOkeNGC_0^OFC*V}KWoM^N9Irl&*_TRjN;OX z3`t;3ML=IAgF_=3r~%}|;>jC1g(nLssU?%=G@upaIB@DbMzhI%TpZhtY8jIvx4(P9 HC?pL4lD%}h delta 1285 zcmah}Ye-XZ6hDVGZEG$Qe7kw=;Va3tDDzP&8c}L#85tDwwM;0d+e|G;`xJf1)brs_ zNP^UdA~EYyi%81oMSV#76a>9s5D_{mqEFVj_imaI$sg`L|NlAX_c(X|P2LFa`58WD zHPH0Z1f3U-$`OV^Jv}h>DI0njv6lLl?F`1Up3lHT!=_}i8f@}w^Y<>Ym50%1uT@_S z<*--G+{Q$*x96!)ZSCWzww8TLlY1(%Q11W*^;~C$h9pnz$wrbo%xcxIu2lw=03=AI zsa<8Vt?Edq=f>9*Dw?s*^~v*z+y!0PG?r_Y1K+2Y2q_l}VvK|WV$D;tzmz`N?ujCDL? zo^UMno-wNA8|G=1$Q`sFqVlLxj;l`xOQ~Z4PAc?UsK~yQB2&WXls9Ze0}FNXe7u~m z=eav+A~VsVj8Wp5E1yh5kU|LH5g)E%G|eVw(p!I|sEorT5tu})ur=apVS0u!a^=~W zgIFOPW0)on`3LOcqZy+p;7_64TP`&ly{2lzZ u81iE*`ya9+2+9^-XrP7nuv^qW!8l=ij`l_1hj0Ez_{0Qm_l=I@%EaF+T4fdh diff --git a/EAPMethods/include/EAPTLS.h b/EAPMethods/include/EAPTLS.h new file mode 100644 index 0000000..e677d42 --- /dev/null +++ b/EAPMethods/include/EAPTLS.h @@ -0,0 +1,181 @@ +/* + Copyright 2015-2016 Amebis + Copyright 2016 GÉANT + + This file is part of GÉANTLink. + + GÉANTLink is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GÉANTLink is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GÉANTLink. If not, see . +*/ + +#include "EAPMethods.h" +#include "EAPSerialize.h" + +namespace eap +{ + class config_tls; +} + +namespace eapserial +{ + inline void pack(_Inout_ unsigned char *&cursor, _In_ const eap::config_tls &val); + inline size_t get_pk_size(const eap::config_tls &val); + inline void unpack(_Inout_ const unsigned char *&cursor, _Out_ eap::config_tls &val); +} + +#pragma once + + +namespace eap +{ + /// + /// TLS configuration + /// + class config_tls : public config_method + { + public: + /// + /// Constructs configuration + /// + /// \param[in] mod Reference of the EAP module to use for global services + /// + config_tls(_In_ module &mod); + + /// + /// Copies configuration + /// + /// \param[in] other Configuration to copy from + /// + config_tls(_In_ const config_tls &other); + + /// + /// Moves configuration + /// + /// \param[in] other Configuration to move from + /// + config_tls(_Inout_ config_tls &&other); + + /// + /// Copies configuration + /// + /// \param[in] other Configuration to copy from + /// + /// \returns Reference to this object + /// + config_tls& operator=(_In_ const config_tls &other); + + /// + /// Moves configuration + /// + /// \param[in] other Configuration to move from + /// + /// \returns Reference to this object + /// + config_tls& operator=(_Inout_ config_tls &&other); + + /// \name XML configuration management + /// @{ + + /// + /// Save configuration to XML document + /// + /// \param[in] pDoc XML document + /// \param[in] pConfigRoot Suggested root element for saving configuration + /// \param[out] ppEapError Pointer to error descriptor in case of failure. Free using `module::free_memory()`. + /// + /// \returns + /// - \c ERROR_SUCCESS if succeeded + /// - error code otherwise + /// + virtual DWORD save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pConfigRoot, _Out_ EAP_ERROR **ppEapError) const; + + /// + /// Load configuration from XML document + /// + /// \param[in] pConfigRoot Root element for loading configuration + /// \param[out] ppEapError Pointer to error descriptor in case of failure. Free using `module::free_memory()`. + /// + /// \returns + /// - \c ERROR_SUCCESS if succeeded + /// - error code otherwise + /// + virtual DWORD load(_In_ IXMLDOMNode *pConfigRoot, _Out_ EAP_ERROR **ppEapError); + + /// @} + + /// + /// Returns EAP method type of this configuration + /// + /// \returns `eap::type_tls` + /// + virtual eap::type_t get_method_id() { return eap::type_tls; } + + /// + /// Adds CA to the list of trusted root CA's + /// + /// \sa [CertCreateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376033.aspx) + /// + bool add_trusted_ca(_In_ DWORD dwCertEncodingType, _In_ const BYTE *pbCertEncoded, _In_ DWORD cbCertEncoded); + + public: + std::list m_trusted_root_ca; ///< Trusted root CAs + std::list m_server_names; ///< Acceptable authenticating server names + }; +} + + +namespace eapserial +{ + /// + /// Packs a TLS method configuration + /// + /// \param[inout] cursor Memory cursor + /// \param[in] val Configuration to pack + /// + inline void pack(_Inout_ unsigned char *&cursor, _In_ const eap::config_tls &val) + { + pack(cursor, (const eap::config_method&)val); + pack(cursor, val.m_trusted_root_ca ); + pack(cursor, val.m_server_names ); + } + + + /// + /// Returns packed size of a TLS method configuration + /// + /// \param[in] val Configuration to pack + /// + /// \returns Size of data when packed (in bytes) + /// + inline size_t get_pk_size(const eap::config_tls &val) + { + return + get_pk_size((const eap::config_method&)val) + + get_pk_size(val.m_trusted_root_ca ) + + get_pk_size(val.m_server_names ); + } + + + /// + /// Unpacks a TLS method configuration + /// + /// \param[inout] cursor Memory cursor + /// \param[out] val Configuration to unpack to + /// + inline void unpack(_Inout_ const unsigned char *&cursor, _Out_ eap::config_tls &val) + { + unpack(cursor, (eap::config_method&)val ); + unpack(cursor, val.m_trusted_root_ca); + unpack(cursor, val.m_server_names ); + } +} diff --git a/EAPMethods/include/EAPTTLS.h b/EAPMethods/include/EAPTTLS.h index 599cd01dbef9787610311d9efebe307a3ea80bd2..6a2228199a5f3ba5c8f76f2ee7b7a72034f5a6ee 100644 GIT binary patch delta 111 zcmZ2CoAJ$pJP(lk2#6 xHh++lV}wgMD2Pl>@L-!!mvP-}#tkKGo9D3=NNkRi*J7Mp$1b<|gMu0}n9-tQrv(5I91SV} diff --git a/EAPMethods/include/StdAfx.h b/EAPMethods/include/StdAfx.h index f41f58d4e9ba4c3b34a607300cae0aa05508279b..9a831f9f4e65c3a39b213f6d22ae3d2f07798970 100644 GIT binary patch delta 20 bcmca6GEH=Y7CW;KL-6EZ6pk&54V~j~)z+f;;rH<DQoqON2-!nEY>d3PF z-u*fE+;hJ3opbMpk5B#L*DpQ!>@FP+x1Zh_rgO-4Mw?&&OH?yk5ef77BUGGYtQ zC7#`|Z+l^YwE1w2ZUfi-hHn2HaMOqV=bEg(J?y8$grmu*j)l&~dMF7E`;)^x^mNWe zA1y4JRvq?9t&>ZB3S4#3pN7vHJvT?T>F=R-`b%=GiAJHto+cxrW8Q{3wLI`pWYN{I zKe{|e|ClqidS21@3hOF$|M}8Ell42sLjQwhpQU^awdi=SlYW-^nx`&0$p0HREi7l1 z<@Wz@<53HJ9Cx~Ji$xI^OJZ5fij>gA9kELXFS|*baJDT~VMY%()@|?4vOdx_U#7wE zFKz9gY+jWR2syg-AO#2F0Mriq*1Mhmazc4~nap zR=~7Xyys6KMvZ3)uSp4-@Jkh{vbg;UJ_U@?#P`Hk#Fz2UA9`IsdnzWP^uy^+`s`Mu zB}&n;PCA?zqLpwz-HWx$-WSB(uZ~s~L{C<6eKF+Vux2Ihm$bpSQ zA}o|ux7aRH^5H}glJCacZPuO_*=zKJ*h{SofX1A-xc{G6SBq_cMYy*r+;q8t8dZkVMmWWT+@&< z4=v(`9zps%x87x4hatQUd0~u zjt16>VU%isHWqM#nBs8o+?Rx4ZbVaWjI#0^(y)$A7Q}>j7yql^zisg*-WfCOpbRz< zz|#U^e;K_~VoW+`$Y2C^Y7TwMR3=jdq|x@^x`ITdE_b(%74ATqViU}uXvzyX={E9v zmJL-L^RMjqX(?HTU!^&n{|Wqefrieu)7y7GlG&xD@T(@-CAiVsFmHTo2A(PSRa|B+iUv8>JR2DW{8J*R9{Z#K=WOz z47&v%Y|z1`2L$~r)rGk(`t;SaZBx)|7i`FR#*oR}3IDn1k27CabPf+)2wL)v#aCG) zsH}3@^qY`>p5>Go9b51yhv+K&R^_TVDuMtoH!m&1ES(0MMv=$(X&TQfcw59%6wfJx zZRgQ4C;M-qmEYoW{u2I~k8AXql7_9*A=?LQAfaM@7TYrtsuVdOuF<1OU(XN#!T?|h z#IThV7Efc@B)}LIvxd915ia+0*eDw|EJLFN7q0_EoZ;B@im}+O86*XjftB&4(G26C z_gQjlO$adrPzKFo4uJ0)XE@e-wL6 z$Q>rIUrt}_lv~jHJ$x6$8`27C@r`4~vgIpUAg!R@7{bE5kTP}vV&9a0oJ5OtC>!m& zFj;`2AGlE=xg=(v#2s`mcOK79GN1W>YSe}Ivs^`082E9qm*Z%}j3blFtnp;FSvU#X zoK#$Q$;x%LBfbdUyKvJgHG%!}`LHn)T1P7_!HVURu;LL3O&GFvd}Y_nmiV9;rV-u4 z{+K@rXEv70rS=9F+gAR(S>?|XEM(R!8iGpMjL#oo0Jhp^S~CJIZM@oN;=zi8np%)C zVDjOOT8_1@BE4Xo;hsUS|x$fg6 zu>{35EX~RnuxJVW)sq^|Y7cVEB2Kp~*Dyrob@^s`yIfmXaTjJ6Zj} z2(lz1m%aMLDgV)A7ac~Nv@vsz9qHwRamfO7>&4Q;A9tR@c4W>LHm=1EhP@$qRVEMT$7csl%teu=hYV|@92ru=%MJ3I?H}YQ3cl^p12fI1y=wW={_K<`l@HqqdPfX z_l7zulBDapFV2=@Z0Z0W*8%F3d;E@N6*-1tGDh}gXUr|yupFGL8Tin6?ZB!#|-^aXF z%wRWN)4AftW!sEno. +*/ + +#include + +using namespace std; +using namespace winstd; + + +////////////////////////////////////////////////////////////////////// +// eap::config_tls +////////////////////////////////////////////////////////////////////// + +eap::config_tls::config_tls(_In_ module &mod) : config_method(mod) +{ +} + + +eap::config_tls::config_tls(_In_ const config_tls &other) : + m_trusted_root_ca(other.m_trusted_root_ca), + m_server_names(other.m_server_names), + config_method(other) +{ +} + + +eap::config_tls::config_tls(_Inout_ config_tls &&other) : + m_trusted_root_ca(std::move(other.m_trusted_root_ca)), + m_server_names(std::move(other.m_server_names)), + config_method(std::move(other)) +{ +} + + +eap::config_tls& eap::config_tls::operator=(_In_ const eap::config_tls &other) +{ + if (this != &other) { + (config_method&)*this = other; + m_trusted_root_ca = other.m_trusted_root_ca; + m_server_names = other.m_server_names; + } + + return *this; +} + + +eap::config_tls& eap::config_tls::operator=(_Inout_ eap::config_tls &&other) +{ + if (this != &other) { + (config_method&&)*this = std::move(other); + m_trusted_root_ca = std::move(other.m_trusted_root_ca); + m_server_names = std::move(other.m_server_names); + } + + return *this; +} + + +DWORD eap::config_tls::save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pConfigRoot, _Out_ EAP_ERROR **ppEapError) const +{ + const bstr bstrNamespace(L"urn:ietf:params:xml:ns:yang:ietf-eap-metadata"); + DWORD dwResult; + HRESULT hr; + + // + com_obj pXmlElServerSideCredential; + if ((dwResult = eapxml::create_element(pDoc, pConfigRoot, bstr(L"eap-metadata:ServerSideCredential"), bstr(L"ServerSideCredential"), bstrNamespace, &pXmlElServerSideCredential)) != ERROR_SUCCESS) { + *ppEapError = m_module.make_error(dwResult, 0, NULL, NULL, NULL, _T(__FUNCTION__) _T(" Error creating element."), NULL); + return dwResult; + } + + for (list::const_iterator i = m_trusted_root_ca.begin(), i_end = m_trusted_root_ca.end(); i != i_end; ++i) { + // + com_obj pXmlElCA; + if ((dwResult = eapxml::create_element(pDoc, bstr(L"CA"), bstrNamespace, &pXmlElCA))) { + *ppEapError = m_module.make_error(dwResult, 0, NULL, NULL, NULL, _T(__FUNCTION__) _T(" Error creating element."), NULL); + return dwResult; + } + + // / + if ((dwResult = eapxml::put_element_value(pDoc, pXmlElCA, bstr(L"format"), bstrNamespace, bstr(L"PEM"))) != ERROR_SUCCESS) { + *ppEapError = m_module.make_error(dwResult, 0, NULL, NULL, NULL, _T(__FUNCTION__) _T(" Error creating element."), NULL); + return dwResult; + } + + // / + const cert_context &cc = *i; + if ((dwResult = eapxml::put_element_base64(pDoc, pXmlElCA, bstr(L"cert-data"), bstrNamespace, cc->pbCertEncoded, cc->cbCertEncoded)) != ERROR_SUCCESS) { + *ppEapError = m_module.make_error(dwResult, 0, NULL, NULL, NULL, _T(__FUNCTION__) _T(" Error creating element."), NULL); + return dwResult; + } + + if (FAILED(hr = pXmlElServerSideCredential->appendChild(pXmlElCA, NULL))) { + *ppEapError = m_module.make_error(dwResult = HRESULT_CODE(hr), 0, NULL, NULL, NULL, _T(__FUNCTION__) _T(" Error appending element."), NULL); + return dwResult; + } + } + + // + for (list::const_iterator i = m_server_names.begin(), i_end = m_server_names.end(); i != i_end; ++i) { + wstring str; + MultiByteToWideChar(CP_UTF8, 0, i->c_str(), (int)i->length(), str); + if ((dwResult = eapxml::put_element_value(pDoc, pXmlElServerSideCredential, bstr(L"ServerName"), bstrNamespace, bstr(str))) != ERROR_SUCCESS) { + *ppEapError = m_module.make_error(dwResult, 0, NULL, NULL, NULL, _T(__FUNCTION__) _T(" Error creating element."), NULL); + return dwResult; + } + } + + return config_method::save(pDoc, pConfigRoot, ppEapError); +} + + +DWORD eap::config_tls::load(_In_ IXMLDOMNode *pConfigRoot, _Out_ EAP_ERROR **ppEapError) +{ + m_trusted_root_ca.clear(); + m_server_names.clear(); + + // + com_obj pXmlElServerSideCredential; + if (eapxml::select_element(pConfigRoot, bstr(L"eap-metadata:ServerSideCredential"), &pXmlElServerSideCredential) == ERROR_SUCCESS) { + // + com_obj pXmlListCAs; + long lCACount = 0; + if (eapxml::select_nodes(pXmlElServerSideCredential, bstr(L"eap-metadata:CA"), &pXmlListCAs) == ERROR_SUCCESS && SUCCEEDED(pXmlListCAs->get_length(&lCACount))) { + for (long j = 0; j < lCACount; j++) { + // Load CA certificate. + com_obj pXmlElCA; + pXmlListCAs->get_item(j, &pXmlElCA); + bstr bstrFormat; + if (eapxml::get_element_value(pXmlElCA, bstr(L"eap-metadata:format"), &bstrFormat) == ERROR_SUCCESS) { + if (CompareStringEx(LOCALE_NAME_INVARIANT, NORM_IGNORECASE, bstrFormat, bstrFormat.length(), L"PEM", -1, NULL, NULL, 0) == CSTR_EQUAL) { + vector aData; + if (eapxml::get_element_base64(pXmlElCA, bstr(L"eap-metadata:cert-data"), aData) == ERROR_SUCCESS) + add_trusted_ca(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, aData.data(), (DWORD)aData.size()); + } + } + } + } + + // + com_obj pXmlListServerIDs; + long lServerIDCount = 0; + if (eapxml::select_nodes(pXmlElServerSideCredential, bstr(L"eap-metadata:ServerName"), &pXmlListServerIDs) == ERROR_SUCCESS && SUCCEEDED(pXmlListServerIDs->get_length(&lServerIDCount))) { + for (long j = 0; j < lServerIDCount; j++) { + // Load server name (). + com_obj pXmlElServerID; + pXmlListServerIDs->get_item(j, &pXmlElServerID); + bstr bstrServerID; + pXmlElServerID->get_text(&bstrServerID); + + // Server names (FQDNs) are always ASCII. Hopefully. Convert them to UTF-8 anyway for consistent comparison. CP_ANSI varies. + string str; + WideCharToMultiByte(CP_UTF8, 0, bstrServerID, bstrServerID.length(), str, NULL, NULL); + + m_server_names.push_back(str); + } + } + } + + return config_method::load(pConfigRoot, ppEapError); +} + + +bool eap::config_tls::add_trusted_ca(_In_ DWORD dwCertEncodingType, _In_ const BYTE *pbCertEncoded, _In_ DWORD cbCertEncoded) +{ + cert_context cert; + if (!cert.create(dwCertEncodingType, pbCertEncoded, cbCertEncoded)) { + // Invalid or unsupported certificate. + return false; + } + + for (list::const_iterator i = m_trusted_root_ca.cbegin(), i_end = m_trusted_root_ca.cend();; ++i) { + if (i != i_end) { + if (*i == cert) { + // This certificate is already on the list. + return false; + } + } else { + // End of list reached. Append certificate. + m_trusted_root_ca.push_back(std::move(cert)); + return true; + } + } +}