openssl 1.1.0
Stefan Küng <[email protected]>
| Newsgroups | gmane.comp.version-control.subversion.tortoisesvn.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi,
Since OpenSSL 1.1.0 is out now, I've got it ready to build with TSVN.
But OpenSSL 1.1.0 is a big change since 1.0.2, so I had to make some
changes to make it build: the ntml-sasl plugin needed some code patches,
and we already have patched the e_capi.c file in openssl for our needs
which needed some more changes as well. Actually, that one required to
include some now internal structs from openssl - those were not internal
in 1.0.2 but we still need those even though they're now private in 1.1.0.
So, I've got the patch ready to get OpenSSL 1.1.0 included in TSVN.
Question is: should I commit that change? Or do we want to stay on the
1.0.x line of OpenSSL?
Stefan
--
___
oo // \\ "De Chelonian Mobile"
(_,\/ \_/ \ TortoiseSVN
\ \_/_\_/> The coolest interface to (Sub)version control
/_/ \_\ http://tortoisesvn.net
------------------------------------------------------
http://tortoisesvn.tigris.org/ds/viewMessage.do?dsForumId=757&dsMessageId=3184522
To unsubscribe from this discussion, e-mail: [[email protected]].
openssl.patch
(text/plain, 24.7 KB)
Index: ext/build/OpenSSL.build
===================================================================
--- ext/build/OpenSSL.build (revision 27411)
+++ ext/build/OpenSSL.build (working copy)
@@ -6,7 +6,7 @@
<echo file="..\openssl\del.bat" message="del %1 %2 %3 %4 %5 %6 %7 %8 %9 /Q" />
<exec program="nmake" workingdir="..\openssl" failonerror="false">
<arg value="-f" />
- <arg value="ms\nt.mak" />
+ <arg value="makefile" />
<arg value="clean" />
</exec>
<delete>
@@ -30,23 +30,21 @@
<arg value="debug-VC-WIN32" if="${configuration == 'debug'}" />
<arg value="no-asm" />
<arg value="no-gost" />
+ <arg value="no-shared" />
<arg value="-DOPENSSL_SSL_CLIENT_ENGINE_AUTO=capi" />
<arg value="-DOPENSSL_CAPIENG_DIALOG" />
+ <arg value="--prefix=${path::get-full-path('ext\openssl\out32')}" />
+ <arg value="--openssldir=out" />
</exec>
- <exec program="cmd" workingdir="..\openssl">
- <arg value="/c" />
- <arg value="ms\do_ms" />
- </exec>
- <loadfile file="..\openssl\ms\nt.mak" property="makefile">
+ <loadfile file="..\openssl\makefile" property="makefile">
<filterchain>
+ <replacestring from="MT=mt" to="MT=md" />
<replacestring from="/MT" to="/MD" />
- <replacestring from="-W3 " to="-W0 " />
- <replacestring from="/Ox " to="/O2 /GL /arch:IA32 " if="${configuration == 'release'}" />
- <replacestring from="lib /nologo" to="lib /nologo /LTCG" if="${configuration == 'release'}" />
- <replacestring from="/opt:ref /debug" to="/opt:ref,icf /debug /LTCG" if="${configuration == 'release'}" />
- <replacestring from="all: banner $(TMP_D) $(BIN_D) $(TEST_D) $(LIB_D) $(INCO_D) headers lib exe" to="all: banner $(TMP_D) $(BIN_D) $(TEST_D) $(LIB_D) $(INCO_D) headers lib" />
+ <replacestring from="-W3" to="-W0" />
</filterchain>
</loadfile>
+ <property name="targetDir" value="..\openssl\out32" if="${configuration == 'release'}" />
+ <property name="targetDir" value="..\openssl\out32.dbg" if="${configuration != 'release'}" />
</if>
<if test="${platform == 'x64'}">
<exec program="perl" workingdir="..\openssl">
@@ -55,33 +53,34 @@
<arg value="debug-VC-WIN64A" if="${configuration == 'debug'}" />
<arg value="no-asm" />
<arg value="no-gost" />
+ <arg value="no-shared" />
<arg value="-DOPENSSL_SSL_CLIENT_ENGINE_AUTO=capi" />
<arg value="-DOPENSSL_CAPIENG_DIALOG" />
+ <arg value="--prefix=${path::get-full-path('ext\openssl\out64')}" />
+ <arg value="--openssldir=out" />
</exec>
- <exec program="cmd" workingdir="..\openssl">
- <arg value="/c" />
- <arg value="ms\do_win64a" />
- </exec>
- <loadfile file="..\openssl\ms\nt.mak" property="makefile">
+ <loadfile file="..\openssl\makefile" property="makefile">
<filterchain>
+ <replacestring from="MT=mt" to="MT=md" />
<replacestring from="/MT" to="/MD" />
- <replacestring from="-W3 " to="-W0 " />
- <replacestring from="/Ox " to="/O2 /GL " if="${configuration == 'release'}" />
- <replacestring from="lib /nologo" to="lib /nologo /LTCG" if="${configuration == 'release'}" />
- <replacestring from="/opt:ref /debug" to="/opt:ref,icf /debug /LTCG" if="${configuration == 'release'}" />
- <replacestring from="OUT_D=out32" to="OUT_D=out64" />
- <replacestring from="TMP_D=tmp32" to="TMP_D=tmp64" />
- <replacestring from="INC_D=inc32" to="INC_D=inc64" />
- <replacestring from="INCO_D=inc32\openssl" to="INCO_D=inc64\openssl" />
- <replacestring from="all: banner $(TMP_D) $(BIN_D) $(TEST_D) $(LIB_D) $(INCO_D) headers lib exe" to="all: banner $(TMP_D) $(BIN_D) $(TEST_D) $(LIB_D) $(INCO_D) headers lib" />
+ <replacestring from="-W3" to="-W0" />
</filterchain>
</loadfile>
+ <property name="targetDir" value="..\openssl\out64" if="${configuration == 'release'}" />
+ <property name="targetDir" value="..\openssl\out64.dbg" if="${configuration != 'release'}" />
</if>
- <echo file="..\openssl\ms\nt.mak" message="${makefile}" />
+ <echo file="..\openssl\makefile" message="${makefile}" />
<exec program="nmake" workingdir="..\openssl">
<arg value="-f" />
- <arg value="ms\nt.mak" />
+ <arg value="makefile" />
+ <arg value="build_libs" />
</exec>
+ <mkdir dir="${targetDir}" />
+ <move todir="${targetDir}">
+ <fileset basedir="..\openssl">
+ <include name="*.lib" />
+ </fileset>
+ </move>
</target>
</project>
Index: ext/build/sasl.build
===================================================================
--- ext/build/sasl.build (revision 27411)
+++ ext/build/sasl.build (working copy)
@@ -222,7 +222,8 @@
<include name="include" />
<include name="plugins" />
<include name="win32\include" />
- <include name="..\openssl\inc${sslplat}" />
+ <include name="..\openssl\include" />
+ <include name="..\openssl\crypto\hmac" />
<include name="..\gssapi" />
</includedirs>
<defines>
@@ -296,7 +297,7 @@
<link
output="${configuration}_${platform}\saslDIGESTMD5.dll"
- options='/INCREMENTAL:NO /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /MANIFESTFILE:"${configuration}_${platform}\saslDIGESTMD5.dll.manifest" /DEBUG /PDB:"${configuration}_${platform}\saslDIGESTMD5.pdb" /DLL ${subsystem} /IMPLIB:"${configuration}_${platform}\saslDIGESTMD5.lib" ${machineoption} ..\openssl\out${sslplat}${ssldbg}\libeay32.lib ..\openssl\out${sslplat}${ssldbg}\ssleay32.lib ${configuration}_${platform}\libsasl.res ws2_32.lib mswsock.lib rpcrt4.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib'>
+ options='/INCREMENTAL:NO /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /MANIFESTFILE:"${configuration}_${platform}\saslDIGESTMD5.dll.manifest" /DEBUG /PDB:"${configuration}_${platform}\saslDIGESTMD5.pdb" /DLL ${subsystem} /IMPLIB:"${configuration}_${platform}\saslDIGESTMD5.lib" ${machineoption} ..\openssl\out${sslplat}${ssldbg}\libcrypto.lib ..\openssl\out${sslplat}${ssldbg}\libssl.lib ${configuration}_${platform}\libsasl.res ws2_32.lib mswsock.lib rpcrt4.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib'>
<arg line="/LTCG /RELEASE /OPT:REF /OPT:ICF" if="${configuration == 'release'}" />
<sources>
<include name="${configuration}_${platform}\plugin_common.obj" />
@@ -342,7 +343,7 @@
<link
output="${configuration}_${platform}\saslNTLM.dll"
- options='/INCREMENTAL:NO /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /MANIFESTFILE:"${configuration}_${platform}\saslNTLM.dll.manifest" /DEBUG /PDB:"${configuration}_${platform}\saslNTLM.pdb" /DLL ${subsystem} /IMPLIB:"${configuration}_${platform}\saslNTLM.lib" ${machineoption} ..\openssl\out${sslplat}${ssldbg}\libeay32.lib ..\openssl\out${sslplat}${ssldbg}\ssleay32.lib ${configuration}_${platform}\libsasl.res ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib'>
+ options='/INCREMENTAL:NO /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /MANIFESTFILE:"${configuration}_${platform}\saslNTLM.dll.manifest" /DEBUG /PDB:"${configuration}_${platform}\saslNTLM.pdb" /DLL ${subsystem} /IMPLIB:"${configuration}_${platform}\saslNTLM.lib" ${machineoption} ..\openssl\out${sslplat}${ssldbg}\libcrypto.lib ..\openssl\out${sslplat}${ssldbg}\libssl.lib ${configuration}_${platform}\libsasl.res Crypt32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib'>
<arg line="/LTCG /RELEASE /OPT:REF /OPT:ICF" if="${configuration == 'release'}" />
<sources>
<include name="${configuration}_${platform}\plugin_common.obj" />
@@ -388,7 +389,7 @@
<link
output="${configuration}_${platform}\saslGSSAPI.dll"
- options='/INCREMENTAL:NO /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /MANIFESTFILE:"${configuration}_${platform}\saslGSSAPI.dll.manifest" /DEBUG /PDB:"${configuration}_${platform}\saslGSSAPI.pdb" /DLL ${subsystem} /IMPLIB:"${configuration}_${platform}\saslGSSAPI.lib" ${machineoption} ..\gssapi\${configuration}_${platform}\gssapiu.lib" ..\openssl\out${sslplat}${ssldbg}\libeay32.lib ..\openssl\out${sslplat}${ssldbg}\ssleay32.lib ${configuration}_${platform}\libsasl.res ws2_32.lib mswsock.lib rpcrt4.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib'>
+ options='/INCREMENTAL:NO /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /MANIFESTFILE:"${configuration}_${platform}\saslGSSAPI.dll.manifest" /DEBUG /PDB:"${configuration}_${platform}\saslGSSAPI.pdb" /DLL ${subsystem} /IMPLIB:"${configuration}_${platform}\saslGSSAPI.lib" ${machineoption} ..\gssapi\${configuration}_${platform}\gssapiu.lib" ..\openssl\out${sslplat}${ssldbg}\libcrypto.lib ..\openssl\out${sslplat}${ssldbg}\libssl.lib ${configuration}_${platform}\libsasl.res ws2_32.lib mswsock.lib rpcrt4.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib'>
<arg line="/LTCG /RELEASE /OPT:REF /OPT:ICF" if="${configuration == 'release'}" />
<sources>
<include name="${configuration}_${platform}\plugin_common.obj" />
Index: ext/build/serf.build
===================================================================
--- ext/build/serf.build (revision 27411)
+++ ext/build/serf.build (working copy)
@@ -57,7 +57,7 @@
<include name="..\apr-util\include" />
<include name="..\apr-util\xml\expat\lib" />
<include name="..\zlib" />
- <include name="..\openssl\inc${sslplat}" />
+ <include name="..\openssl\include" />
</includedirs>
<defines>
<define name="APR_DECLARE_EXPORT" />
@@ -89,8 +89,8 @@
<sources>
<include name="${configuration}_${platform}\*.obj" />
<include name="..\zlib\${configuration}_${platform}\zlibstat.lib" />
- <include name="..\openssl\out${sslplat}${ssldbg}\libeay32.lib" />
- <include name="..\openssl\out${sslplat}${ssldbg}\ssleay32.lib" />
+ <include name="..\openssl\out${sslplat}${ssldbg}\libcrypto.lib" />
+ <include name="..\openssl\out${sslplat}${ssldbg}\libssl.lib" />
<include name="..\apr-util\${configuration}_${platform}\libaprutil_tsvn.lib" />
<include name="..\apr\${configuration}_${platform}\libapr_tsvn.lib" />
</sources>
Index: ext/build/subversion.build
===================================================================
--- ext/build/subversion.build (revision 27411)
+++ ext/build/subversion.build (working copy)
@@ -282,9 +282,7 @@
</foreach>
<property name="deffilecontent" value ='${deffilecontent}
EXPORTS
-ERR_free_strings
-EVP_cleanup
-CRYPTO_cleanup_all_ex_data
+OPENSSL_cleanup
TSVN_ClearLastUsedAuthCache' />
<echo file="${configuration}_${platform}\libsvn_tsvn${platext}.def" message="${deffilecontent}" />
@@ -308,7 +306,7 @@
</rc>
<link
output="${configuration}_${platform}\libsvn_tsvn${platext}.dll"
- options='/INCREMENTAL:NO /ERRORREPORT:QUEUE /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /DEF:"${configuration}_${platform}\libsvn_tsvn${platext}.def" /MANIFESTFILE:"${configuration}_${platform}\libsvn_tsvn${platext}.dll.intermediate.manifest" /DEBUG /PDB:"${configuration}_${platform}\libsvn_tsvn${platext}.pdb" /DLL ${subsystem} /IMPLIB:"${configuration}_${platform}\libsvn_tsvn${platext}.lib" ${machineoption} ${configuration}_${platform}\svn.res ..\apr\${configuration}_${platform}\libapr_tsvn.lib ..\apr-util\${configuration}_${platform}\libaprutil_tsvn.lib ..\serf\${configuration}_${platform}\libserf.lib ..\zlib\${configuration}_${platform}\zlibstat.lib ..\openssl\out${sslplat}${ssldbg}\libeay32.lib ..\openssl\out${sslplat}${ssldbg}\ssleay32.lib ..\libintl\${configuration}_${platform}\lib\intl3_tsvn.lib ..\cyrus-SASL\${configuration}_${platform}\libsasl.lib ..\sqlite\${configuration}_${platform}\sqlite.lib ws2_32.lib mswsock.lib rpcrt4.lib kernel32.lib advapi32.lib gdi32.lib user32.lib shell32.lib ole32.lib Secur32.lib Crypt32.lib Psapi.lib Version.lib'>
+ options='/INCREMENTAL:NO /ERRORREPORT:QUEUE /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /DEF:"${configuration}_${platform}\libsvn_tsvn${platext}.def" /MANIFESTFILE:"${configuration}_${platform}\libsvn_tsvn${platext}.dll.intermediate.manifest" /DEBUG /PDB:"${configuration}_${platform}\libsvn_tsvn${platext}.pdb" /DLL ${subsystem} /IMPLIB:"${configuration}_${platform}\libsvn_tsvn${platext}.lib" ${machineoption} ${configuration}_${platform}\svn.res ..\apr\${configuration}_${platform}\libapr_tsvn.lib ..\apr-util\${configuration}_${platform}\libaprutil_tsvn.lib ..\serf\${configuration}_${platform}\libserf.lib ..\zlib\${configuration}_${platform}\zlibstat.lib ..\openssl\out${sslplat}${ssldbg}\libcrypto.lib ..\openssl\out${sslplat}${ssldbg}\libssl.lib ..\libintl\${configuration}_${platform}\lib\intl3_tsvn.lib ..\cyrus-SASL\${configuration}_${platform}\libsasl.lib ..\sqlite\${configuration}_${platform}\sqlite.lib ws2_32.lib mswsock.lib rpcrt4.lib kernel32.lib advapi32.lib gdi32.lib user32.lib shell32.lib ole32.lib Secur32.lib Crypt32.lib Psapi.lib Version.lib'>
<arg line="/LTCG /RELEASE /OPT:REF /OPT:ICF" if="${configuration == 'release'}" />
<sources>
<include name="${configuration}_${platform}\libsvn_*\**.obj" />
@@ -418,7 +416,7 @@
<echo message="now linking ${toolname}" />
<link
output="${configuration}_${platform}\${toolname}.exe"
- options='/INCREMENTAL:NO /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /MANIFESTFILE:"${configuration}_${platform}\${toolname}.exe.intermediate.manifest" /DEBUG /PDB:"${configuration}_${platform}\${toolname}.pdb" ${subsystemcl} ${configuration}_${platform}\libsvn_tsvn${platext}.lib ..\apr\${configuration}_${platform}\libapr_tsvn.lib ..\apr-util\${configuration}_${platform}\libaprutil_tsvn.lib ..\serf\${configuration}_${platform}\libserf.lib ..\zlib\${configuration}_${platform}\zlibstat.lib ..\openssl\out${sslplat}${ssldbg}\libeay32.lib ..\openssl\out${sslplat}${ssldbg}\ssleay32.lib ..\libintl\${configuration}_${platform}\lib\intl3_tsvn.lib ..\cyrus-SASL\${configuration}_${platform}\libsasl.lib ${machineoption} ${configuration}_${platform}\svn.res ${machineoption} ws2_32.lib mswsock.lib rpcrt4.lib kernel32.lib advapi32.lib gdi32.lib user32.lib shell32.lib ole32.lib Secur32.lib Crypt32.lib Psapi.lib Version.lib setargv.obj'>
+ options='/INCREMENTAL:NO /NOLOGO /DYNAMICBASE /NXCOMPAT /MANIFEST /MANIFESTFILE:"${configuration}_${platform}\${toolname}.exe.intermediate.manifest" /DEBUG /PDB:"${configuration}_${platform}\${toolname}.pdb" ${subsystemcl} ${configuration}_${platform}\libsvn_tsvn${platext}.lib ..\apr\${configuration}_${platform}\libapr_tsvn.lib ..\apr-util\${configuration}_${platform}\libaprutil_tsvn.lib ..\serf\${configuration}_${platform}\libserf.lib ..\zlib\${configuration}_${platform}\zlibstat.lib ..\openssl\out${sslplat}${ssldbg}\libcrypto.lib ..\openssl\out${sslplat}${ssldbg}\libssl.lib ..\libintl\${configuration}_${platform}\lib\intl3_tsvn.lib ..\cyrus-SASL\${configuration}_${platform}\libsasl.lib ${machineoption} ${configuration}_${platform}\svn.res ${machineoption} ws2_32.lib mswsock.lib rpcrt4.lib kernel32.lib advapi32.lib gdi32.lib user32.lib shell32.lib ole32.lib Secur32.lib Crypt32.lib Psapi.lib Version.lib setargv.obj'>
<arg line="/LTCG /RELEASE /OPT:REF /OPT:ICF" if="${configuration == 'release'}" />
<sources>
<include name="${configuration}_${platform}\${toolname}\*.obj" />
Index: ext/cyrus-SASL/plugins/ntlm.c
===================================================================
--- ext/cyrus-SASL/plugins/ntlm.c (revision 27411)
+++ ext/cyrus-SASL/plugins/ntlm.c (working copy)
@@ -76,6 +76,7 @@
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/hmac.h>
+#include <hmac_lcl.h>
#include <openssl/des.h>
#include <openssl/opensslv.h>
#if (OPENSSL_VERSION_NUMBER >= 0x0090700f) && \
@@ -453,7 +454,7 @@
HMAC_Update(&ctx, challenge, NTLM_NONCE_LENGTH);
HMAC_Update(&ctx, blob, bloblen);
HMAC_Final(&ctx, V2, &len);
- HMAC_cleanup(&ctx);
+ /*HMAC_cleanup(&ctx);*/
/* the blob is concatenated outside of this function */
Index: src/TortoiseProc/AboutDlg.cpp
===================================================================
--- src/TortoiseProc/AboutDlg.cpp (revision 27411)
+++ src/TortoiseProc/AboutDlg.cpp (working copy)
@@ -24,6 +24,7 @@
#include "../version.h"
#include "../../ext/serf/serf.h"
#include "../../ext/sqlite/sqlite3.h"
+#include "../../ext/openssl/include/openssl/opensslv.h"
#include "AppUtils.h"
IMPLEMENT_DYNAMIC(CAboutDlg, CStandAloneDialog)
Index: src/TortoiseProc/stdafx.h
===================================================================
--- src/TortoiseProc/stdafx.h (revision 27411)
+++ src/TortoiseProc/stdafx.h (working copy)
@@ -88,11 +88,6 @@
#include "apr_version.h"
#include "apu_version.h"
-#ifdef _WIN64
-#include "openssl/opensslv.h"
-#else
-#include "openssl/opensslv.h"
-#endif
#include "../../ext/zlib/zlib.h"
#define __WIN32__
Index: src/TortoiseProc/TortoiseProc.cpp
===================================================================
--- src/TortoiseProc/TortoiseProc.cpp (revision 27411)
+++ src/TortoiseProc/TortoiseProc.cpp (working copy)
@@ -34,8 +34,7 @@
#include "SVNGlobal.h"
#include "svn_types.h"
#include "svn_dso.h"
-#include "openssl/ssl.h"
-#include "openssl/err.h"
+#include "openssl/crypto.h"
#include "Commands/Command.h"
#include "../version.h"
#include "JumpListHelpers.h"
@@ -87,9 +86,7 @@
// global application exit cleanup (after all SSL activity is shutdown)
// we have to clean up SSL ourselves, since serf doesn't do that (can't do it)
// because those cleanup functions work globally per process.
- ERR_free_strings();
- EVP_cleanup();
- CRYPTO_cleanup_all_ex_data();
+ OPENSSL_cleanup();
// since it is undefined *when* the global object SVNAdminDir is
// destroyed, we tell it to destroy the memory pools and terminate apr
Index: src/TortoiseProc/TortoiseProc.vcxproj
===================================================================
--- src/TortoiseProc/TortoiseProc.vcxproj (revision 27411)
+++ src/TortoiseProc/TortoiseProc.vcxproj (working copy)
@@ -80,7 +80,7 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>..\..\ext\apr-util\include;..\..\ext\apr-util\xml\expat\lib;..\..\ext\Subversion\subversion\include;..\..\ext\Subversion\subversion\libsvn_client;..\..\ext\apr\include;..\..\ext\boost;..\TortoiseProc;..\Utils;..\SVN;..\..\ext\ResizableLib;..\TortoiseShell;..\..\ext\libintl\gettext-0.14.6\gettext-runtime\intl;..\..\ext\scintilla\include;..\..\ext\TreePropSheet;..\Utils\ColourPickerXP;..\Utils\NewMenu;..\Utils\MiscUI;..\LogCache;..\LogCache\Containers;..\AsyncFramework;..\..\ext\cyrus-sasl\include;..\..\ext\openssl\inc32;RevisionGraph;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\ext\apr-util\include;..\..\ext\apr-util\xml\expat\lib;..\..\ext\Subversion\subversion\include;..\..\ext\Subversion\subversion\libsvn_client;..\..\ext\apr\include;..\..\ext\boost;..\..\ext\openssl\include;..\TortoiseProc;..\Utils;..\SVN;..\..\ext\ResizableLib;..\TortoiseShell;..\..\ext\libintl\gettext-0.14.6\gettext-runtime\intl;..\..\ext\scintilla\include;..\..\ext\TreePropSheet;..\Utils\ColourPickerXP;..\Utils\NewMenu;..\Utils\MiscUI;..\LogCache;..\LogCache\Containers;..\AsyncFramework;..\..\ext\cyrus-sasl\include;..\..\ext\openssl\inc32;RevisionGraph;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>HUNSPELL_STATIC;SVN_DEBUG;THESAURUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
@@ -93,7 +93,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>..\..\ext\apr-util\include;..\..\ext\apr-util\xml\expat\lib;..\..\ext\Subversion\subversion\include;..\..\ext\Subversion\subversion\libsvn_client;..\..\ext\apr\include;..\..\ext\boost;..\TortoiseProc;..\Utils;..\SVN;..\..\ext\ResizableLib;..\TortoiseShell;..\..\ext\libintl\gettext-0.14.6\gettext-runtime\intl;..\..\ext\scintilla\include;..\..\ext\TreePropSheet;..\Utils\ColourPickerXP;..\Utils\NewMenu;..\Utils\MiscUI;..\LogCache;..\LogCache\Containers;..\AsyncFramework;..\..\ext\cyrus-sasl\include;..\..\ext\openssl\inc64;RevisionGraph;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\ext\apr-util\include;..\..\ext\apr-util\xml\expat\lib;..\..\ext\Subversion\subversion\include;..\..\ext\Subversion\subversion\libsvn_client;..\..\ext\apr\include;..\..\ext\boost;..\..\ext\openssl\include;..\TortoiseProc;..\Utils;..\SVN;..\..\ext\ResizableLib;..\TortoiseShell;..\..\ext\libintl\gettext-0.14.6\gettext-runtime\intl;..\..\ext\scintilla\include;..\..\ext\TreePropSheet;..\Utils\ColourPickerXP;..\Utils\NewMenu;..\Utils\MiscUI;..\LogCache;..\LogCache\Containers;..\AsyncFramework;..\..\ext\cyrus-sasl\include;..\..\ext\openssl\inc64;RevisionGraph;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>HUNSPELL_STATIC;SVN_DEBUG;THESAURUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
@@ -106,7 +106,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>..\..\ext\apr-util\include;..\..\ext\apr-util\xml\expat\lib;..\..\ext\Subversion\subversion\include;..\..\ext\Subversion\subversion\libsvn_client;..\..\ext\apr\include;..\..\ext\boost;..\TortoiseProc;..\Utils;..\SVN;..\..\ext\ResizableLib;..\TortoiseShell;..\..\ext\libintl\gettext-0.14.6\gettext-runtime\intl;..\..\ext\scintilla\include;..\..\ext\TreePropSheet;..\Utils\ColourPickerXP;..\Utils\NewMenu;..\Utils\MiscUI;..\LogCache;..\LogCache\Containers;..\AsyncFramework;..\..\ext\cyrus-sasl\include;..\..\ext\openssl\inc32;RevisionGraph;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\ext\apr-util\include;..\..\ext\apr-util\xml\expat\lib;..\..\ext\Subversion\subversion\include;..\..\ext\Subversion\subversion\libsvn_client;..\..\ext\apr\include;..\..\ext\boost;..\..\ext\openssl\include;..\TortoiseProc;..\Utils;..\SVN;..\..\ext\ResizableLib;..\TortoiseShell;..\..\ext\libintl\gettext-0.14.6\gettext-runtime\intl;..\..\ext\scintilla\include;..\..\ext\TreePropSheet;..\Utils\ColourPickerXP;..\Utils\NewMenu;..\Utils\MiscUI;..\LogCache;..\LogCache\Containers;..\AsyncFramework;..\..\ext\cyrus-sasl\include;..\..\ext\openssl\inc32;RevisionGraph;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>HUNSPELL_STATIC;THESAURUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
@@ -119,7 +119,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>..\..\ext\apr-util\include;..\..\ext\apr-util\xml\expat\lib;..\..\ext\Subversion\subversion\include;..\..\ext\Subversion\subversion\libsvn_client;..\..\ext\apr\include;..\..\ext\boost;..\TortoiseProc;..\Utils;..\SVN;..\..\ext\ResizableLib;..\TortoiseShell;..\..\ext\libintl\gettext-0.14.6\gettext-runtime\intl;..\..\ext\scintilla\include;..\..\ext\TreePropSheet;..\Utils\ColourPickerXP;..\Utils\NewMenu;..\Utils\MiscUI;..\LogCache;..\LogCache\Containers;..\AsyncFramework;..\..\ext\cyrus-sasl\include;..\..\ext\openssl\inc64;RevisionGraph;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\ext\apr-util\include;..\..\ext\apr-util\xml\expat\lib;..\..\ext\Subversion\subversion\include;..\..\ext\Subversion\subversion\libsvn_client;..\..\ext\apr\include;..\..\ext\boost;..\..\ext\openssl\include;..\TortoiseProc;..\Utils;..\SVN;..\..\ext\ResizableLib;..\TortoiseShell;..\..\ext\libintl\gettext-0.14.6\gettext-runtime\intl;..\..\ext\scintilla\include;..\..\ext\TreePropSheet;..\Utils\ColourPickerXP;..\Utils\NewMenu;..\Utils\MiscUI;..\LogCache;..\LogCache\Containers;..\AsyncFramework;..\..\ext\cyrus-sasl\include;..\..\ext\openssl\inc64;RevisionGraph;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>HUNSPELL_STATIC;THESAURUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
e_capi.c
(text/plain, 60.6 KB)
/*
* Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifdef _WIN32
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0600
# endif
# include <windows.h>
# include <wincrypt.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <malloc.h>
# include <shlwapi.h>
# ifndef alloca
# define alloca _alloca
# endif
# pragma comment(lib, "shlwapi.lib")
# include <openssl/crypto.h>
# ifndef OPENSSL_NO_CAPIENG
# include <openssl/buffer.h>
# include <openssl/bn.h>
# include <openssl/rsa.h>
# include <openssl/dsa.h>
struct X509_name_st {
STACK_OF(X509_NAME_ENTRY) *entries; /* DN components */
int modified; /* true if 'bytes' needs to be built */
BUF_MEM *bytes; /* cached encoding: cannot be NULL */
/* canonical encoding used for rapid Name comparison */
unsigned char *canon_enc;
int canon_enclen;
} /* X509_NAME */ ;
/*
* This module uses several "new" interfaces, among which is
* CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is
* one of possible values you can pass to function in question. By
* checking if it's defined we can see if wincrypt.h and accompanying
* crypt32.lib are in shape. The native MingW32 headers up to and
* including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the
* defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG,
* so we check for these too and avoid compiling.
* Yes, it's rather "weak" test and if compilation fails,
* then re-configure with -DOPENSSL_NO_CAPIENG.
*/
# if defined(CERT_KEY_PROV_INFO_PROP_ID) && \
defined(CERT_STORE_PROV_SYSTEM_A) && \
defined(CERT_STORE_READONLY_FLAG)
# define __COMPILE_CAPIENG
# endif /* CERT_KEY_PROV_INFO_PROP_ID */
# endif /* OPENSSL_NO_CAPIENG */
#endif /* _WIN32 */
#ifdef __COMPILE_CAPIENG
# undef X509_EXTENSIONS
/* Definitions which may be missing from earlier version of headers */
# ifndef CERT_STORE_OPEN_EXISTING_FLAG
# define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
# endif
# ifndef CERT_STORE_CREATE_NEW_FLAG
# define CERT_STORE_CREATE_NEW_FLAG 0x00002000
# endif
# ifndef CERT_SYSTEM_STORE_CURRENT_USER
# define CERT_SYSTEM_STORE_CURRENT_USER 0x00010000
# endif
# ifndef ALG_SID_SHA_256
# define ALG_SID_SHA_256 12
# endif
# ifndef ALG_SID_SHA_384
# define ALG_SID_SHA_384 13
# endif
# ifndef ALG_SID_SHA_512
# define ALG_SID_SHA_512 14
# endif
# ifndef CALG_SHA_256
# define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
# endif
# ifndef CALG_SHA_384
# define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)
# endif
# ifndef CALG_SHA_512
# define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)
# endif
# ifndef PROV_RSA_AES
# define PROV_RSA_AES 24
# endif
# include <openssl/engine.h>
# include <openssl/pem.h>
# include <openssl/x509v3.h>
# include "e_capi_err.h"
# include "e_capi_err.c"
char lastUsedAuthCacheHash[100] = {0};
void TSVN_GetSHA1HashFromX509(STACK_OF(X509_NAME) *ca_dn, char * outbuf)
{
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
DWORD cbHash = 0;
BYTE rgbHash[20];
char sha1hashstring[50];
CHAR rgbDigits[] = "0123456789abcdef";
int i;
X509_NAME * nm;
outbuf[0] = 0;
if (CryptAcquireContext(&hProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
if (CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
{
for (i = 0; i < sk_X509_NAME_num(ca_dn); ++i)
{
nm = sk_X509_NAME_value(ca_dn, i);
CryptHashData(hHash, nm->canon_enc, nm->canon_enclen, 0);
}
cbHash = 20;
if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
{
for (i = 0; i < (int)cbHash; ++i)
{
sha1hashstring[i*2] = rgbDigits[rgbHash[i] >> 4];
sha1hashstring[i*2+1] = rgbDigits[rgbHash[i] & 0xf];
}
sha1hashstring[cbHash] = 0;
strcpy(outbuf, sha1hashstring);
}
CryptDestroyHash(hHash);
}
CryptReleaseContext(hProv, 0);
}
}
int TSVN_GetSavedIndexForHash(const char* hash)
{
int ret = -1;
DWORD dwType = 0;
DWORD dwData = 0;
DWORD dwDataSize = 4;
int bLoad = 1;
if (SHGetValueA(HKEY_CURRENT_USER, "Software\\TortoiseSVN\\CAPIAuthz", hash, &dwType, &dwData, &dwDataSize) == ERROR_SUCCESS)
{
if (dwType == REG_DWORD)
{
ret = (int)dwData;
}
}
return ret;
}
void TSVN_SaveIndexForHash(const char* hash, int index)
{
DWORD value = index;
SHSetValueA(HKEY_CURRENT_USER, "Software\\TortoiseSVN\\CAPIAuthz", hash, REG_DWORD, &value, sizeof(value));
}
void TSVN_ClearLastUsedAuthCache()
{
SHDeleteValueA(HKEY_CURRENT_USER, "Software\\TortoiseSVN\\CAPIAuthz", lastUsedAuthCacheHash);
}
BOOL CALLBACK FindWindoProc(HWND hwnd, LPARAM lParam)
{
HWND * pWnd;
DWORD pid = 0;
if ((GetWindowLongPtr(hwnd, GWL_STYLE) & WS_VISIBLE))
{
GetWindowThreadProcessId(hwnd, &pid);
if (pid == GetCurrentProcessId())
{
pWnd = (HWND*)lParam;
(*pWnd) = hwnd;
return FALSE;
}
}
return TRUE;
}
static const char *engine_capi_id = "capi";
static const char *engine_capi_name = "CryptoAPI ENGINE";
typedef struct CAPI_CTX_st CAPI_CTX;
typedef struct CAPI_KEY_st CAPI_KEY;
static void capi_addlasterror(void);
static void capi_adderror(DWORD err);
static void CAPI_trace(CAPI_CTX * ctx, char *format, ...);
static int capi_list_providers(CAPI_CTX * ctx, BIO *out);
static int capi_list_containers(CAPI_CTX * ctx, BIO *out);
int capi_list_certs(CAPI_CTX * ctx, BIO *out, char *storename);
void capi_free_key(CAPI_KEY * key);
static PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id,
HCERTSTORE hstore);
CAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id);
static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
UI_METHOD *ui_method, void *callback_data);
static int capi_rsa_sign(int dtype, const unsigned char *m,
unsigned int m_len, unsigned char *sigret,
unsigned int *siglen, const RSA *rsa);
static int capi_rsa_priv_enc(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
static int capi_rsa_priv_dec(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
static int capi_rsa_free(RSA *rsa);
# ifndef OPENSSL_NO_DSA
static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
DSA *dsa);
static int capi_dsa_free(DSA *dsa);
# endif
static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
EVP_PKEY **pkey, STACK_OF(X509) **pother,
UI_METHOD *ui_method,
void *callback_data);
static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
# ifdef OPENSSL_CAPIENG_DIALOG
static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
# endif
void engine_load_capi_int(void);
typedef PCCERT_CONTEXT(WINAPI *CERTDLG) (HCERTSTORE, HWND, LPCWSTR,
LPCWSTR, DWORD, DWORD, void *);
typedef HWND(WINAPI *GETCONSWIN) (void);
/*
* This structure contains CAPI ENGINE specific data: it contains various
* global options and affects how other functions behave.
*/
# define CAPI_DBG_TRACE 2
# define CAPI_DBG_ERROR 1
struct CAPI_CTX_st {
int debug_level;
char *debug_file;
/* Parameters to use for container lookup */
DWORD keytype;
LPSTR cspname;
DWORD csptype;
/* Certificate store name to use */
LPSTR storename;
LPSTR ssl_client_store;
/* System store flags */
DWORD store_flags;
/* Lookup string meanings in load_private_key */
/* Substring of subject: uses "storename" */
# define CAPI_LU_SUBSTR 1
/* Friendly name: uses storename */
# define CAPI_LU_FNAME 2
/* Container name: uses cspname, keytype */
# define CAPI_LU_CONTNAME 3
int lookup_method;
/* Info to dump with dumpcerts option */
/* Issuer and serial name strings */
# define CAPI_DMP_SUMMARY 0x1
/* Friendly name */
# define CAPI_DMP_FNAME 0x2
/* Full X509_print dump */
# define CAPI_DMP_FULL 0x4
/* Dump PEM format certificate */
# define CAPI_DMP_PEM 0x8
/* Dump pseudo key (if possible) */
# define CAPI_DMP_PSKEY 0x10
/* Dump key info (if possible) */
# define CAPI_DMP_PKEYINFO 0x20
DWORD dump_flags;
int (*client_cert_select) (ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
CERTDLG certselectdlg;
GETCONSWIN getconswindow;
};
static CAPI_CTX *capi_ctx_new(void);
static void capi_ctx_free(CAPI_CTX * ctx);
static int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type,
int check);
static int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx);
# define CAPI_CMD_LIST_CERTS ENGINE_CMD_BASE
# define CAPI_CMD_LOOKUP_CERT (ENGINE_CMD_BASE + 1)
# define CAPI_CMD_DEBUG_LEVEL (ENGINE_CMD_BASE + 2)
# define CAPI_CMD_DEBUG_FILE (ENGINE_CMD_BASE + 3)
# define CAPI_CMD_KEYTYPE (ENGINE_CMD_BASE + 4)
# define CAPI_CMD_LIST_CSPS (ENGINE_CMD_BASE + 5)
# define CAPI_CMD_SET_CSP_IDX (ENGINE_CMD_BASE + 6)
# define CAPI_CMD_SET_CSP_NAME (ENGINE_CMD_BASE + 7)
# define CAPI_CMD_SET_CSP_TYPE (ENGINE_CMD_BASE + 8)
# define CAPI_CMD_LIST_CONTAINERS (ENGINE_CMD_BASE + 9)
# define CAPI_CMD_LIST_OPTIONS (ENGINE_CMD_BASE + 10)
# define CAPI_CMD_LOOKUP_METHOD (ENGINE_CMD_BASE + 11)
# define CAPI_CMD_STORE_NAME (ENGINE_CMD_BASE + 12)
# define CAPI_CMD_STORE_FLAGS (ENGINE_CMD_BASE + 13)
static const ENGINE_CMD_DEFN capi_cmd_defns[] = {
{CAPI_CMD_LIST_CERTS,
"list_certs",
"List all certificates in store",
ENGINE_CMD_FLAG_NO_INPUT},
{CAPI_CMD_LOOKUP_CERT,
"lookup_cert",
"Lookup and output certificates",
ENGINE_CMD_FLAG_STRING},
{CAPI_CMD_DEBUG_LEVEL,
"debug_level",
"debug level (1=errors, 2=trace)",
ENGINE_CMD_FLAG_NUMERIC},
{CAPI_CMD_DEBUG_FILE,
"debug_file",
"debugging filename)",
ENGINE_CMD_FLAG_STRING},
{CAPI_CMD_KEYTYPE,
"key_type",
"Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE",
ENGINE_CMD_FLAG_NUMERIC},
{CAPI_CMD_LIST_CSPS,
"list_csps",
"List all CSPs",
ENGINE_CMD_FLAG_NO_INPUT},
{CAPI_CMD_SET_CSP_IDX,
"csp_idx",
"Set CSP by index",
ENGINE_CMD_FLAG_NUMERIC},
{CAPI_CMD_SET_CSP_NAME,
"csp_name",
"Set CSP name, (default CSP used if not specified)",
ENGINE_CMD_FLAG_STRING},
{CAPI_CMD_SET_CSP_TYPE,
"csp_type",
"Set CSP type, (default RSA_PROV_FULL)",
ENGINE_CMD_FLAG_NUMERIC},
{CAPI_CMD_LIST_CONTAINERS,
"list_containers",
"list container names",
ENGINE_CMD_FLAG_NO_INPUT},
{CAPI_CMD_LIST_OPTIONS,
"list_options",
"Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, "
"32=private key info)",
ENGINE_CMD_FLAG_NUMERIC},
{CAPI_CMD_LOOKUP_METHOD,
"lookup_method",
"Set key lookup method (1=substring, 2=friendlyname, 3=container name)",
ENGINE_CMD_FLAG_NUMERIC},
{CAPI_CMD_STORE_NAME,
"store_name",
"certificate store name, default \"MY\"",
ENGINE_CMD_FLAG_STRING},
{CAPI_CMD_STORE_FLAGS,
"store_flags",
"Certificate store flags: 1 = system store",
ENGINE_CMD_FLAG_NUMERIC},
{0, NULL, NULL, 0}
};
static int capi_idx = -1;
static int rsa_capi_idx = -1;
static int dsa_capi_idx = -1;
static int cert_capi_idx = -1;
static int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
{
int ret = 1;
CAPI_CTX *ctx;
BIO *out;
LPSTR tmpstr;
if (capi_idx == -1) {
CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED);
return 0;
}
ctx = ENGINE_get_ex_data(e, capi_idx);
out = BIO_new_fp(stdout, BIO_NOCLOSE);
if (out == NULL) {
CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_FILE_OPEN_ERROR);
return 0;
}
switch (cmd) {
case CAPI_CMD_LIST_CSPS:
ret = capi_list_providers(ctx, out);
break;
case CAPI_CMD_LIST_CERTS:
ret = capi_list_certs(ctx, out, NULL);
break;
case CAPI_CMD_LOOKUP_CERT:
ret = capi_list_certs(ctx, out, p);
break;
case CAPI_CMD_LIST_CONTAINERS:
ret = capi_list_containers(ctx, out);
break;
case CAPI_CMD_STORE_NAME:
tmpstr = OPENSSL_strdup(p);
if (tmpstr != NULL) {
OPENSSL_free(ctx->storename);
ctx->storename = tmpstr;
CAPI_trace(ctx, "Setting store name to %s\n", p);
} else {
CAPIerr(CAPI_F_CAPI_CTRL, ERR_R_MALLOC_FAILURE);
ret = 0;
}
break;
case CAPI_CMD_STORE_FLAGS:
if (i & 1) {
ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
} else {
ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER;
ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE;
}
CAPI_trace(ctx, "Setting flags to %d\n", i);
break;
case CAPI_CMD_DEBUG_LEVEL:
ctx->debug_level = (int)i;
CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level);
break;
case CAPI_CMD_DEBUG_FILE:
tmpstr = OPENSSL_strdup(p);
if (tmpstr != NULL) {
ctx->debug_file = tmpstr;
CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file);
} else {
CAPIerr(CAPI_F_CAPI_CTRL, ERR_R_MALLOC_FAILURE);
ret = 0;
}
break;
case CAPI_CMD_KEYTYPE:
ctx->keytype = i;
CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype);
break;
case CAPI_CMD_SET_CSP_IDX:
ret = capi_ctx_set_provname_idx(ctx, i);
break;
case CAPI_CMD_LIST_OPTIONS:
ctx->dump_flags = i;
break;
case CAPI_CMD_LOOKUP_METHOD:
if (i < 1 || i > 3) {
CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD);
BIO_free(out);
return 0;
}
ctx->lookup_method = i;
break;
case CAPI_CMD_SET_CSP_NAME:
ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1);
break;
case CAPI_CMD_SET_CSP_TYPE:
ctx->csptype = i;
break;
default:
CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND);
ret = 0;
}
BIO_free(out);
return ret;
}
static RSA_METHOD *capi_rsa_method = NULL;
# ifndef OPENSSL_NO_DSA
static DSA_METHOD *capi_dsa_method = NULL;
# endif
static int use_aes_csp = 0;
static int capi_init(ENGINE *e)
{
CAPI_CTX *ctx;
const RSA_METHOD *ossl_rsa_meth;
# ifndef OPENSSL_NO_DSA
const DSA_METHOD *ossl_dsa_meth;
# endif
HCRYPTPROV hprov;
if (capi_idx < 0) {
capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
if (capi_idx < 0)
goto memerr;
cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0);
/* Setup RSA_METHOD */
rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
ossl_rsa_meth = RSA_PKCS1_OpenSSL();
if ( !RSA_meth_set_pub_enc(capi_rsa_method,
RSA_meth_get_pub_enc(ossl_rsa_meth))
|| !RSA_meth_set_pub_dec(capi_rsa_method,
RSA_meth_get_pub_dec(ossl_rsa_meth))
|| !RSA_meth_set_priv_enc(capi_rsa_method, capi_rsa_priv_enc)
|| !RSA_meth_set_priv_dec(capi_rsa_method, capi_rsa_priv_dec)
|| !RSA_meth_set_mod_exp(capi_rsa_method,
RSA_meth_get_mod_exp(ossl_rsa_meth))
|| !RSA_meth_set_bn_mod_exp(capi_rsa_method,
RSA_meth_get_bn_mod_exp(ossl_rsa_meth))
|| !RSA_meth_set_finish(capi_rsa_method, capi_rsa_free)
|| !RSA_meth_set_sign(capi_rsa_method, capi_rsa_sign)) {
goto memerr;
}
# ifndef OPENSSL_NO_DSA
/* Setup DSA Method */
dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
ossl_dsa_meth = DSA_OpenSSL();
if ( !DSA_meth_set_sign(capi_dsa_method, capi_dsa_do_sign)
|| !DSA_meth_set_verify(capi_dsa_method,
DSA_meth_get_verify(ossl_dsa_meth))
|| !DSA_meth_set_finish(capi_dsa_method, capi_dsa_free)
|| !DSA_meth_set_mod_exp(capi_dsa_method,
DSA_meth_get_mod_exp(ossl_dsa_meth))
|| !DSA_meth_set_bn_mod_exp(capi_dsa_method,
DSA_meth_get_bn_mod_exp(ossl_dsa_meth))) {
goto memerr;
}
# endif
}
ctx = capi_ctx_new();
if (ctx == NULL)
goto memerr;
ENGINE_set_ex_data(e, capi_idx, ctx);
# ifdef OPENSSL_CAPIENG_DIALOG
{
HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL"));
HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL"));
if (cryptui)
ctx->certselectdlg =
(CERTDLG) GetProcAddress(cryptui,
"CryptUIDlgSelectCertificateFromStore");
if (kernel)
ctx->getconswindow =
(GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow");
if (cryptui && !OPENSSL_isservice())
ctx->client_cert_select = cert_select_dialog;
}
# endif
/* See if we support AES CSP */
if (CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_AES,
CRYPT_VERIFYCONTEXT)) {
use_aes_csp = 1;
CryptReleaseContext(hprov, 0);
}
return 1;
memerr:
CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE);
return 0;
return 1;
}
static int capi_destroy(ENGINE *e)
{
RSA_meth_free(capi_rsa_method);
capi_rsa_method = NULL;
# ifndef OPENSSL_NO_DSA
DSA_meth_free(capi_dsa_method);
capi_dsa_method = NULL;
# endif
ERR_unload_CAPI_strings();
return 1;
}
static int capi_finish(ENGINE *e)
{
CAPI_CTX *ctx;
ctx = ENGINE_get_ex_data(e, capi_idx);
capi_ctx_free(ctx);
ENGINE_set_ex_data(e, capi_idx, NULL);
return 1;
}
/*
* CryptoAPI key application data. This contains a handle to the private key
* container (for sign operations) and a handle to the key (for decrypt
* operations).
*/
struct CAPI_KEY_st {
/* Associated certificate context (if any) */
PCCERT_CONTEXT pcert;
HCRYPTPROV hprov;
HCRYPTKEY key;
DWORD keyspec;
};
static int bind_capi(ENGINE *e)
{
capi_rsa_method = RSA_meth_new("CryptoAPI RSA method", 0);
if (capi_rsa_method == NULL)
return 0;
# ifndef OPENSSL_NO_DSA
capi_dsa_method = DSA_meth_new("CryptoAPI DSA method", 0);
if (capi_dsa_method == NULL)
goto memerr;
# endif
if (!ENGINE_set_id(e, engine_capi_id)
|| !ENGINE_set_name(e, engine_capi_name)
|| !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL)
|| !ENGINE_set_init_function(e, capi_init)
|| !ENGINE_set_finish_function(e, capi_finish)
|| !ENGINE_set_destroy_function(e, capi_destroy)
|| !ENGINE_set_RSA(e, capi_rsa_method)
# ifndef OPENSSL_NO_DSA
|| !ENGINE_set_DSA(e, capi_dsa_method)
# endif
|| !ENGINE_set_load_privkey_function(e, capi_load_privkey)
|| !ENGINE_set_load_ssl_client_cert_function(e,
capi_load_ssl_client_cert)
|| !ENGINE_set_cmd_defns(e, capi_cmd_defns)
|| !ENGINE_set_ctrl_function(e, capi_ctrl))
goto memerr;
ERR_load_CAPI_strings();
return 1;
memerr:
RSA_meth_free(capi_rsa_method);
capi_rsa_method = NULL;
# ifndef OPENSSL_NO_DSA
DSA_meth_free(capi_dsa_method);
capi_dsa_method = NULL;
# endif
return 0;
}
# ifndef OPENSSL_NO_DYNAMIC_ENGINE
static int bind_helper(ENGINE *e, const char *id)
{
if (id && (strcmp(id, engine_capi_id) != 0))
return 0;
if (!bind_capi(e))
return 0;
return 1;
}
IMPLEMENT_DYNAMIC_CHECK_FN()
IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
# else
static ENGINE *engine_capi(void)
{
ENGINE *ret = ENGINE_new();
if (ret == NULL)
return NULL;
if (!bind_capi(ret)) {
ENGINE_free(ret);
return NULL;
}
return ret;
}
void engine_load_capi_int(void)
{
DWORD dwType = 0;
DWORD dwData = 0;
DWORD dwDataSize = 4;
int bLoad = 1;
if (SHGetValueA(HKEY_CURRENT_USER, "Software\\TortoiseSVN", "OpenSSLCapi", &dwType, &dwData, &dwDataSize) == ERROR_SUCCESS)
{
if (dwType == REG_DWORD)
{
if (dwData == 0)
{
bLoad = 0;
}
}
}
if (bLoad)
{
/* Copied from eng_[openssl|dyn].c */
ENGINE *toadd = engine_capi();
if (!toadd)
return;
ENGINE_add(toadd);
ENGINE_free(toadd);
ERR_clear_error();
}
}
# endif
static int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen)
{
int i;
/*
* Reverse buffer in place: since this is a keyblob structure that will
* be freed up after conversion anyway it doesn't matter if we change
* it.
*/
for (i = 0; i < binlen / 2; i++) {
unsigned char c;
c = bin[i];
bin[i] = bin[binlen - i - 1];
bin[binlen - i - 1] = c;
}
if (!BN_bin2bn(bin, binlen, bn))
return 0;
return 1;
}
/* Given a CAPI_KEY get an EVP_PKEY structure */
static EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY * key)
{
unsigned char *pubkey = NULL;
DWORD len;
BLOBHEADER *bh;
RSA *rkey = NULL;
DSA *dkey = NULL;
EVP_PKEY *ret = NULL;
if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) {
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR);
capi_addlasterror();
return NULL;
}
pubkey = OPENSSL_malloc(len);
if (pubkey == NULL)
goto memerr;
if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) {
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
capi_addlasterror();
goto err;
}
bh = (BLOBHEADER *) pubkey;
if (bh->bType != PUBLICKEYBLOB) {
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB);
goto err;
}
if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) {
RSAPUBKEY *rp;
DWORD rsa_modlen;
BIGNUM *e = NULL, *n = NULL;
unsigned char *rsa_modulus;
rp = (RSAPUBKEY *) (bh + 1);
if (rp->magic != 0x31415352) {
char magstr[10];
BIO_snprintf(magstr, 10, "%lx", rp->magic);
CAPIerr(CAPI_F_CAPI_GET_PKEY,
CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
ERR_add_error_data(2, "magic=0x", magstr);
goto err;
}
rsa_modulus = (unsigned char *)(rp + 1);
rkey = RSA_new_method(eng);
if (!rkey)
goto memerr;
e = BN_new();
n = BN_new();
if (e == NULL || n == NULL) {
BN_free(e);
BN_free(n);
goto memerr;
}
RSA_set0_key(rkey, n, e, NULL);
if (!BN_set_word(e, rp->pubexp))
goto memerr;
rsa_modlen = rp->bitlen / 8;
if (!lend_tobn(n, rsa_modulus, rsa_modlen))
goto memerr;
RSA_set_ex_data(rkey, rsa_capi_idx, key);
if ((ret = EVP_PKEY_new()) == NULL)
goto memerr;
EVP_PKEY_assign_RSA(ret, rkey);
rkey = NULL;
# ifndef OPENSSL_NO_DSA
} else if (bh->aiKeyAlg == CALG_DSS_SIGN) {
DSSPUBKEY *dp;
DWORD dsa_plen;
unsigned char *btmp;
BIGNUM *p, *q, *g, *pub_key;
dp = (DSSPUBKEY *) (bh + 1);
if (dp->magic != 0x31535344) {
char magstr[10];
BIO_snprintf(magstr, 10, "%lx", dp->magic);
CAPIerr(CAPI_F_CAPI_GET_PKEY,
CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
ERR_add_error_data(2, "magic=0x", magstr);
goto err;
}
dsa_plen = dp->bitlen / 8;
btmp = (unsigned char *)(dp + 1);
dkey = DSA_new_method(eng);
if (!dkey)
goto memerr;
p = BN_new();
q = BN_new();
g = BN_new();
pub_key = BN_new();
if (p == NULL || q == NULL || g == NULL || pub_key == NULL) {
BN_free(p);
BN_free(q);
BN_free(g);
BN_free(pub_key);
goto memerr;
}
DSA_set0_pqg(dkey, p, q, g);
DSA_set0_key(dkey, pub_key, NULL);
if (!lend_tobn(p, btmp, dsa_plen))
goto memerr;
btmp += dsa_plen;
if (!lend_tobn(q, btmp, 20))
goto memerr;
btmp += 20;
if (!lend_tobn(g, btmp, dsa_plen))
goto memerr;
btmp += dsa_plen;
if (!lend_tobn(pub_key, btmp, dsa_plen))
goto memerr;
btmp += dsa_plen;
DSA_set_ex_data(dkey, dsa_capi_idx, key);
if ((ret = EVP_PKEY_new()) == NULL)
goto memerr;
EVP_PKEY_assign_DSA(ret, dkey);
dkey = NULL;
# endif
} else {
char algstr[10];
BIO_snprintf(algstr, 10, "%ux", bh->aiKeyAlg);
CAPIerr(CAPI_F_CAPI_GET_PKEY,
CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM);
ERR_add_error_data(2, "aiKeyAlg=0x", algstr);
goto err;
}
err:
OPENSSL_free(pubkey);
if (!ret) {
RSA_free(rkey);
# ifndef OPENSSL_NO_DSA
DSA_free(dkey);
# endif
}
return ret;
memerr:
CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE);
goto err;
}
static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
UI_METHOD *ui_method, void *callback_data)
{
CAPI_CTX *ctx;
CAPI_KEY *key;
EVP_PKEY *ret;
ctx = ENGINE_get_ex_data(eng, capi_idx);
if (!ctx) {
CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT);
return NULL;
}
key = capi_find_key(ctx, key_id);
if (!key)
return NULL;
ret = capi_get_pkey(eng, key);
if (!ret)
capi_free_key(key);
return ret;
}
/* CryptoAPI RSA operations */
int capi_rsa_priv_enc(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED);
return -1;
}
int capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
{
ALG_ID alg;
HCRYPTHASH hash;
DWORD slen;
unsigned int i;
int ret = -1;
CAPI_KEY *capi_key;
CAPI_CTX *ctx;
ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx);
CAPI_trace(ctx, "Called CAPI_rsa_sign()\n");
capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
if (!capi_key) {
CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY);
return -1;
}
/* Convert the signature type to a CryptoAPI algorithm ID */
switch (dtype) {
case NID_sha256:
alg = CALG_SHA_256;
break;
case NID_sha384:
alg = CALG_SHA_384;
break;
case NID_sha512:
alg = CALG_SHA_512;
break;
case NID_sha1:
alg = CALG_SHA1;
break;
case NID_md5:
alg = CALG_MD5;
break;
case NID_md5_sha1:
alg = CALG_SSL3_SHAMD5;
break;
default:
{
char algstr[10];
BIO_snprintf(algstr, 10, "%x", dtype);
CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID);
ERR_add_error_data(2, "NID=0x", algstr);
return -1;
}
}
/* Create the hash object */
if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) {
CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
capi_addlasterror();
return -1;
}
/* Set the hash value to the value passed */
if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) {
CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
capi_addlasterror();
goto err;
}
/* Finally sign it */
slen = RSA_size(rsa);
if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) {
CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH);
capi_addlasterror();
goto err;
} else {
ret = 1;
/* Inplace byte reversal of signature */
for (i = 0; i < slen / 2; i++) {
unsigned char c;
c = sigret[i];
sigret[i] = sigret[slen - i - 1];
sigret[slen - i - 1] = c;
}
*siglen = slen;
}
/* Now cleanup */
err:
CryptDestroyHash(hash);
return ret;
}
int capi_rsa_priv_dec(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
int i;
unsigned char *tmpbuf;
CAPI_KEY *capi_key;
CAPI_CTX *ctx;
DWORD dlen;
if (flen <= 0)
return flen;
ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx);
CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n");
capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
if (!capi_key) {
CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY);
return -1;
}
if (padding != RSA_PKCS1_PADDING) {
char errstr[10];
BIO_snprintf(errstr, 10, "%d", padding);
CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING);
ERR_add_error_data(2, "padding=", errstr);
return -1;
}
/* Create temp reverse order version of input */
if ((tmpbuf = OPENSSL_malloc(flen)) == NULL) {
CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE);
return -1;
}
for (i = 0; i < flen; i++)
tmpbuf[flen - i - 1] = from[i];
/* Finally decrypt it */
dlen = flen;
if (!CryptDecrypt(capi_key->key, 0, TRUE, 0, tmpbuf, &dlen)) {
CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR);
capi_addlasterror();
OPENSSL_free(tmpbuf);
return -1;
} else
memcpy(to, tmpbuf, (flen = (int)dlen));
OPENSSL_free(tmpbuf);
return flen;
}
static int capi_rsa_free(RSA *rsa)
{
CAPI_KEY *capi_key;
capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
capi_free_key(capi_key);
RSA_set_ex_data(rsa, rsa_capi_idx, 0);
return 1;
}
# ifndef OPENSSL_NO_DSA
/* CryptoAPI DSA operations */
static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
DSA *dsa)
{
HCRYPTHASH hash;
DWORD slen;
DSA_SIG *ret = NULL;
CAPI_KEY *capi_key;
CAPI_CTX *ctx;
unsigned char csigbuf[40];
ctx = ENGINE_get_ex_data(DSA_get0_engine(dsa), capi_idx);
CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n");
capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
if (!capi_key) {
CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY);
return NULL;
}
if (dlen != 20) {
CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH);
return NULL;
}
/* Create the hash object */
if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) {
CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
capi_addlasterror();
return NULL;
}
/* Set the hash value to the value passed */
if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) {
CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
capi_addlasterror();
goto err;
}
/* Finally sign it */
slen = sizeof(csigbuf);
if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) {
CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH);
capi_addlasterror();
goto err;
} else {
BIGNUM *r = BN_new(), *s = BN_new();
if (r == NULL || s == NULL
|| !lend_tobn(r, csigbuf, 20)
|| !lend_tobn(s, csigbuf + 20, 20)
|| (ret = DSA_SIG_new()) == NULL) {
BN_free(r); /* BN_free checks for BIGNUM * being NULL */
BN_free(s);
goto err;
}
DSA_SIG_set0(ret, r, s);
}
/* Now cleanup */
err:
OPENSSL_cleanse(csigbuf, 40);
CryptDestroyHash(hash);
return ret;
}
static int capi_dsa_free(DSA *dsa)
{
CAPI_KEY *capi_key;
capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
capi_free_key(capi_key);
DSA_set_ex_data(dsa, dsa_capi_idx, 0);
return 1;
}
# endif
static void capi_vtrace(CAPI_CTX * ctx, int level, char *format,
va_list argptr)
{
BIO *out;
if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file))
return;
out = BIO_new_file(ctx->debug_file, "a+");
if (out == NULL) {
CAPIerr(CAPI_F_CAPI_VTRACE, CAPI_R_FILE_OPEN_ERROR);
return;
}
BIO_vprintf(out, format, argptr);
BIO_free(out);
}
static void CAPI_trace(CAPI_CTX * ctx, char *format, ...)
{
va_list args;
va_start(args, format);
capi_vtrace(ctx, CAPI_DBG_TRACE, format, args);
va_end(args);
}
static void capi_addlasterror(void)
{
capi_adderror(GetLastError());
}
static void capi_adderror(DWORD err)
{
char errstr[10];
BIO_snprintf(errstr, 10, "%lX", err);
ERR_add_error_data(2, "Error code= 0x", errstr);
}
static char *wide_to_asc(LPCWSTR wstr)
{
char *str;
int len_0, sz;
if (!wstr)
return NULL;
len_0 = (int)wcslen(wstr) + 1; /* WideCharToMultiByte expects int */
sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL);
if (!sz) {
CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
return NULL;
}
str = OPENSSL_malloc(sz);
if (str == NULL) {
CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE);
return NULL;
}
if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) {
OPENSSL_free(str);
CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
return NULL;
}
return str;
}
static int capi_get_provname(CAPI_CTX * ctx, LPSTR * pname, DWORD * ptype,
DWORD idx)
{
DWORD len, err;
LPTSTR name;
CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx);
if (!CryptEnumProviders(idx, NULL, 0, ptype, NULL, &len)) {
err = GetLastError();
if (err == ERROR_NO_MORE_ITEMS)
return 2;
CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
capi_adderror(err);
return 0;
}
name = OPENSSL_malloc(len);
if (name == NULL) {
CAPIerr(CAPI_F_CAPI_GET_PROVNAME, ERR_R_MALLOC_FAILURE);
return 0;
}
if (!CryptEnumProviders(idx, NULL, 0, ptype, name, &len)) {
err = GetLastError();
OPENSSL_free(name);
if (err == ERROR_NO_MORE_ITEMS)
return 2;
CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
capi_adderror(err);
return 0;
}
if (sizeof(TCHAR) != sizeof(char)) {
*pname = wide_to_asc((WCHAR *)name);
OPENSSL_free(name);
if (*pname == NULL)
return 0;
} else
*pname = (char *)name;
CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", *pname,
*ptype);
return 1;
}
static int capi_list_providers(CAPI_CTX * ctx, BIO *out)
{
DWORD idx, ptype;
int ret;
LPSTR provname = NULL;
CAPI_trace(ctx, "capi_list_providers\n");
BIO_printf(out, "Available CSPs:\n");
for (idx = 0;; idx++) {
ret = capi_get_provname(ctx, &provname, &ptype, idx);
if (ret == 2)
break;
if (ret == 0)
break;
BIO_printf(out, "%lu. %s, type %lu\n", idx, provname, ptype);
OPENSSL_free(provname);
}
return 1;
}
static int capi_list_containers(CAPI_CTX * ctx, BIO *out)
{
int ret = 1;
HCRYPTPROV hprov;
DWORD err, idx, flags, buflen = 0, clen;
LPSTR cname;
LPTSTR cspname = NULL;
CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname,
ctx->csptype);
if (ctx->cspname && sizeof(TCHAR) != sizeof(char)) {
if ((clen =
MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, NULL, 0))) {
cspname = alloca(clen * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, (WCHAR *)cspname,
clen);
}
if (!cspname) {
CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
capi_addlasterror();
return 0;
}
} else
cspname = (TCHAR *)ctx->cspname;
if (!CryptAcquireContext
(&hprov, NULL, cspname, ctx->csptype, CRYPT_VERIFYCONTEXT)) {
CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS,
CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
capi_addlasterror();
return 0;
}
if (!CryptGetProvParam
(hprov, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST)) {
CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
capi_addlasterror();
CryptReleaseContext(hprov, 0);
return 0;
}
CAPI_trace(ctx, "Got max container len %d\n", buflen);
if (buflen == 0)
buflen = 1024;
cname = OPENSSL_malloc(buflen);
if (cname == NULL) {
CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
goto err;
}
for (idx = 0;; idx++) {
clen = buflen;
cname[0] = 0;
if (idx == 0)
flags = CRYPT_FIRST;
else
flags = 0;
if (!CryptGetProvParam
(hprov, PP_ENUMCONTAINERS, (BYTE *) cname, &clen, flags)) {
err = GetLastError();
if (err == ERROR_NO_MORE_ITEMS)
goto done;
CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
capi_adderror(err);
goto err;
}
CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n",
cname, clen, idx, flags);
if (!cname[0] && (clen == buflen)) {
CAPI_trace(ctx, "Enumerate bug: using workaround\n");
goto done;
}
BIO_printf(out, "%lu. %s\n", idx, cname);
}
err:
ret = 0;
done:
OPENSSL_free(cname);
CryptReleaseContext(hprov, 0);
return ret;
}
static CRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
{
DWORD len;
CRYPT_KEY_PROV_INFO *pinfo;
if (!CertGetCertificateContextProperty
(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len))
return NULL;
pinfo = OPENSSL_malloc(len);
if (pinfo == NULL) {
CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE);
return NULL;
}
if (!CertGetCertificateContextProperty
(cert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) {
CAPIerr(CAPI_F_CAPI_GET_PROV_INFO,
CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO);
capi_addlasterror();
OPENSSL_free(pinfo);
return NULL;
}
return pinfo;
}
static void capi_dump_prov_info(CAPI_CTX * ctx, BIO *out,
CRYPT_KEY_PROV_INFO * pinfo)
{
char *provname = NULL, *contname = NULL;
if (!pinfo) {
BIO_printf(out, " No Private Key\n");
return;
}
provname = wide_to_asc(pinfo->pwszProvName);
contname = wide_to_asc(pinfo->pwszContainerName);
if (!provname || !contname)
goto err;
BIO_printf(out, " Private Key Info:\n");
BIO_printf(out, " Provider Name: %s, Provider Type %lu\n", provname,
pinfo->dwProvType);
BIO_printf(out, " Container Name: %s, Key Type %lu\n", contname,
pinfo->dwKeySpec);
err:
OPENSSL_free(provname);
OPENSSL_free(contname);
}
static char *capi_cert_get_fname(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
{
LPWSTR wfname;
DWORD dlen;
CAPI_trace(ctx, "capi_cert_get_fname\n");
if (!CertGetCertificateContextProperty
(cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &dlen))
return NULL;
wfname = OPENSSL_malloc(dlen);
if (wfname == NULL)
return NULL;
if (CertGetCertificateContextProperty
(cert, CERT_FRIENDLY_NAME_PROP_ID, wfname, &dlen)) {
char *fname = wide_to_asc(wfname);
OPENSSL_free(wfname);
return fname;
}
CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME);
capi_addlasterror();
OPENSSL_free(wfname);
return NULL;
}
static void capi_dump_cert(CAPI_CTX * ctx, BIO *out, PCCERT_CONTEXT cert)
{
X509 *x;
const unsigned char *p;
unsigned long flags = ctx->dump_flags;
if (flags & CAPI_DMP_FNAME) {
char *fname;
fname = capi_cert_get_fname(ctx, cert);
if (fname) {
BIO_printf(out, " Friendly Name \"%s\"\n", fname);
OPENSSL_free(fname);
} else
BIO_printf(out, " <No Friendly Name>\n");
}
p = cert->pbCertEncoded;
x = d2i_X509(NULL, &p, cert->cbCertEncoded);
if (!x)
BIO_printf(out, " <Can't parse certificate>\n");
if (flags & CAPI_DMP_SUMMARY) {
BIO_printf(out, " Subject: ");
X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
BIO_printf(out, "\n Issuer: ");
X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
BIO_printf(out, "\n");
}
if (flags & CAPI_DMP_FULL)
X509_print_ex(out, x, XN_FLAG_ONELINE, 0);
if (flags & CAPI_DMP_PKEYINFO) {
CRYPT_KEY_PROV_INFO *pinfo;
pinfo = capi_get_prov_info(ctx, cert);
capi_dump_prov_info(ctx, out, pinfo);
OPENSSL_free(pinfo);
}
if (flags & CAPI_DMP_PEM)
PEM_write_bio_X509(out, x);
X509_free(x);
}
static HCERTSTORE capi_open_store(CAPI_CTX * ctx, char *storename)
{
HCERTSTORE hstore;
if (!storename)
storename = ctx->storename;
if (!storename)
storename = "MY";
CAPI_trace(ctx, "Opening certificate store %s\n", storename);
hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
ctx->store_flags, storename);
if (!hstore) {
CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE);
capi_addlasterror();
}
return hstore;
}
int capi_list_certs(CAPI_CTX * ctx, BIO *out, char *id)
{
char *storename;
int idx;
int ret = 1;
HCERTSTORE hstore;
PCCERT_CONTEXT cert = NULL;
storename = ctx->storename;
if (!storename)
storename = "MY";
CAPI_trace(ctx, "Listing certs for store %s\n", storename);
hstore = capi_open_store(ctx, storename);
if (!hstore)
return 0;
if (id) {
cert = capi_find_cert(ctx, id, hstore);
if (!cert) {
ret = 0;
goto err;
}
capi_dump_cert(ctx, out, cert);
CertFreeCertificateContext(cert);
} else {
for (idx = 0;; idx++) {
cert = CertEnumCertificatesInStore(hstore, cert);
if (!cert)
break;
BIO_printf(out, "Certificate %d\n", idx);
capi_dump_cert(ctx, out, cert);
}
}
err:
CertCloseStore(hstore, 0);
return ret;
}
static PCCERT_CONTEXT capi_find_cert(CAPI_CTX * ctx, const char *id,
HCERTSTORE hstore)
{
PCCERT_CONTEXT cert = NULL;
char *fname = NULL;
int match;
switch (ctx->lookup_method) {
case CAPI_LU_SUBSTR:
return CertFindCertificateInStore(hstore,
X509_ASN_ENCODING, 0,
CERT_FIND_SUBJECT_STR_A, id, NULL);
case CAPI_LU_FNAME:
for (;;) {
cert = CertEnumCertificatesInStore(hstore, cert);
if (!cert)
return NULL;
fname = capi_cert_get_fname(ctx, cert);
if (fname) {
if (strcmp(fname, id))
match = 0;
else
match = 1;
OPENSSL_free(fname);
if (match)
return cert;
}
}
default:
return NULL;
}
}
static CAPI_KEY *capi_get_key(CAPI_CTX * ctx, const TCHAR *contname,
TCHAR *provname, DWORD ptype, DWORD keyspec)
{
DWORD dwFlags = 0;
CAPI_KEY *key = OPENSSL_malloc(sizeof(*key));
if (key == NULL)
return NULL;
/* If PROV_RSA_AES supported use it instead */
if (ptype == PROV_RSA_FULL && use_aes_csp) {
provname = NULL;
ptype = PROV_RSA_AES;
CAPI_trace(ctx, "capi_get_key, contname=%s, RSA_AES_CSP\n", contname);
} else if (sizeof(TCHAR) == sizeof(char)) {
CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n",
contname, provname, ptype);
} else if (ctx && ctx->debug_level >= CAPI_DBG_TRACE && ctx->debug_file) {
/* above 'if' is optimization to minimize malloc-ations */
char *_contname = wide_to_asc((WCHAR *)contname);
char *_provname = wide_to_asc((WCHAR *)provname);
CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n",
_contname, _provname, ptype);
OPENSSL_free(_provname);
OPENSSL_free(_contname);
}
if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE)
dwFlags = CRYPT_MACHINE_KEYSET;
// first try enhanced version
if(!CryptAcquireContext(&key->hprov, contname, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, dwFlags))
{
if (!CryptAcquireContext(&key->hprov, contname, provname, ptype, dwFlags)) {
CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
capi_addlasterror();
goto err;
}
}
if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) {
CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR);
capi_addlasterror();
CryptReleaseContext(key->hprov, 0);
goto err;
}
key->keyspec = keyspec;
key->pcert = NULL;
return key;
err:
OPENSSL_free(key);
return NULL;
}
static CAPI_KEY *capi_get_cert_key(CAPI_CTX * ctx, PCCERT_CONTEXT cert)
{
CAPI_KEY *key = NULL;
CRYPT_KEY_PROV_INFO *pinfo = NULL;
char *provname = NULL, *contname = NULL;
pinfo = capi_get_prov_info(ctx, cert);
if (!pinfo)
goto err;
if (sizeof(TCHAR) != sizeof(char))
key = capi_get_key(ctx, (TCHAR *)pinfo->pwszContainerName,
(TCHAR *)pinfo->pwszProvName,
pinfo->dwProvType, pinfo->dwKeySpec);
else {
provname = wide_to_asc(pinfo->pwszProvName);
contname = wide_to_asc(pinfo->pwszContainerName);
if (!provname || !contname)
goto err;
key = capi_get_key(ctx, (TCHAR *)contname, (TCHAR *)provname,
pinfo->dwProvType, pinfo->dwKeySpec);
}
err:
OPENSSL_free(pinfo);
OPENSSL_free(provname);
OPENSSL_free(contname);
return key;
}
CAPI_KEY *capi_find_key(CAPI_CTX * ctx, const char *id)
{
PCCERT_CONTEXT cert;
HCERTSTORE hstore;
CAPI_KEY *key = NULL;
switch (ctx->lookup_method) {
case CAPI_LU_SUBSTR:
case CAPI_LU_FNAME:
hstore = capi_open_store(ctx, NULL);
if (!hstore)
return NULL;
cert = capi_find_cert(ctx, id, hstore);
if (cert) {
key = capi_get_cert_key(ctx, cert);
CertFreeCertificateContext(cert);
}
CertCloseStore(hstore, 0);
break;
case CAPI_LU_CONTNAME:
if (sizeof(TCHAR) != sizeof(char)) {
WCHAR *contname, *provname;
DWORD len;
if ((len = MultiByteToWideChar(CP_ACP, 0, id, -1, NULL, 0)) &&
(contname = alloca(len * sizeof(WCHAR)),
MultiByteToWideChar(CP_ACP, 0, id, -1, contname, len)) &&
(len =
MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, NULL, 0))
&& (provname =
alloca(len * sizeof(WCHAR)), MultiByteToWideChar(CP_ACP,
0,
ctx->cspname,
-1,
provname,
len)))
key =
capi_get_key(ctx, (TCHAR *)contname, (TCHAR *)provname,
ctx->csptype, ctx->keytype);
} else
key = capi_get_key(ctx, (TCHAR *)id,
(TCHAR *)ctx->cspname,
ctx->csptype, ctx->keytype);
break;
}
return key;
}
void capi_free_key(CAPI_KEY * key)
{
if (!key)
return;
CryptDestroyKey(key->key);
CryptReleaseContext(key->hprov, 0);
if (key->pcert)
CertFreeCertificateContext(key->pcert);
OPENSSL_free(key);
}
/* Initialize a CAPI_CTX structure */
static CAPI_CTX *capi_ctx_new(void)
{
CAPI_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx == NULL) {
CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE);
return NULL;
}
ctx->csptype = PROV_RSA_FULL;
ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME;
ctx->keytype = AT_KEYEXCHANGE;
ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG |
CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER;
ctx->lookup_method = CAPI_LU_SUBSTR;
ctx->client_cert_select = cert_select_simple;
return ctx;
}
static void capi_ctx_free(CAPI_CTX * ctx)
{
CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx);
if (!ctx)
return;
OPENSSL_free(ctx->cspname);
OPENSSL_free(ctx->debug_file);
OPENSSL_free(ctx->storename);
OPENSSL_free(ctx->ssl_client_store);
OPENSSL_free(ctx);
}
static int capi_ctx_set_provname(CAPI_CTX * ctx, LPSTR pname, DWORD type,
int check)
{
LPSTR tmpcspname;
CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type);
if (check) {
HCRYPTPROV hprov;
LPTSTR name = NULL;
if (sizeof(TCHAR) != sizeof(char)) {
DWORD len;
if ((len = MultiByteToWideChar(CP_ACP, 0, pname, -1, NULL, 0))) {
name = alloca(len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, pname, -1, (WCHAR *)name, len);
}
} else
name = (TCHAR *)pname;
if (!name || !CryptAcquireContext(&hprov, NULL, name, type,
CRYPT_VERIFYCONTEXT)) {
CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME,
CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
capi_addlasterror();
return 0;
}
CryptReleaseContext(hprov, 0);
}
tmpcspname = OPENSSL_strdup(pname);
if (tmpcspname == NULL) {
CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, ERR_R_MALLOC_FAILURE);
return 0;
}
OPENSSL_free(ctx->cspname);
ctx->cspname = tmpcspname;
ctx->csptype = type;
return 1;
}
static int capi_ctx_set_provname_idx(CAPI_CTX * ctx, int idx)
{
LPSTR pname;
DWORD type;
int res;
if (capi_get_provname(ctx, &pname, &type, idx) != 1)
return 0;
res = capi_ctx_set_provname(ctx, pname, type, 0);
OPENSSL_free(pname);
return res;
}
static int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x)
{
int i;
X509_NAME *nm;
/* Special case: empty list: match anything */
if (sk_X509_NAME_num(ca_dn) <= 0)
return 1;
for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) {
nm = sk_X509_NAME_value(ca_dn, i);
if (!X509_NAME_cmp(nm, X509_get_issuer_name(x)))
return 1;
}
return 0;
}
static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
EVP_PKEY **pkey, STACK_OF(X509) **pother,
UI_METHOD *ui_method,
void *callback_data)
{
STACK_OF(X509) *certs = NULL;
X509 *x;
char *storename;
const unsigned char *p;
int i, client_cert_idx;
HCERTSTORE hstore;
PCCERT_CONTEXT cert = NULL, excert = NULL;
CAPI_CTX *ctx;
CAPI_KEY *key;
char hash[100];
ctx = ENGINE_get_ex_data(e, capi_idx);
*pcert = NULL;
*pkey = NULL;
storename = ctx->ssl_client_store;
if (!storename)
storename = "MY";
hstore = capi_open_store(ctx, storename);
if (!hstore)
return 0;
/* Enumerate all certificates collect any matches */
for (i = 0;; i++) {
cert = CertEnumCertificatesInStore(hstore, cert);
if (!cert)
break;
p = cert->pbCertEncoded;
x = d2i_X509(NULL, &p, cert->cbCertEncoded);
if (!x) {
CAPI_trace(ctx, "Can't Parse Certificate %d\n", i);
continue;
}
if (cert_issuer_match(ca_dn, x)
&& X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) {
key = capi_get_cert_key(ctx, cert);
if (!key) {
X509_free(x);
continue;
}
/*
* Match found: attach extra data to it so we can retrieve the
* key later.
*/
excert = CertDuplicateCertificateContext(cert);
key->pcert = excert;
X509_set_ex_data(x, cert_capi_idx, key);
if (!certs)
certs = sk_X509_new_null();
sk_X509_push(certs, x);
} else
X509_free(x);
}
if (cert)
CertFreeCertificateContext(cert);
if (hstore)
CertCloseStore(hstore, 0);
if (!certs)
return 0;
/* Select the appropriate certificate */
TSVN_GetSHA1HashFromX509(ca_dn, hash);
strcpy(lastUsedAuthCacheHash, hash);
client_cert_idx = TSVN_GetSavedIndexForHash(hash);
if ((client_cert_idx < 0) || (client_cert_idx >= sk_X509_num(certs)))
{
client_cert_idx = ctx->client_cert_select(e, ssl, certs);
if (client_cert_idx >= 0)
{
TSVN_SaveIndexForHash(hash, client_cert_idx);
}
}
else if (client_cert_idx >= sk_X509_num(certs))
{
TSVN_ClearLastUsedAuthCache();
}
/* Set the selected certificate and free the rest */
for (i = 0; i < sk_X509_num(certs); i++) {
x = sk_X509_value(certs, i);
if (i == client_cert_idx)
*pcert = x;
else {
key = X509_get_ex_data(x, cert_capi_idx);
capi_free_key(key);
X509_free(x);
}
}
sk_X509_free(certs);
if (!*pcert)
return 0;
/* Setup key for selected certificate */
key = X509_get_ex_data(*pcert, cert_capi_idx);
*pkey = capi_get_pkey(e, key);
X509_set_ex_data(*pcert, cert_capi_idx, NULL);
return 1;
}
/* Simple client cert selection function: always select first */
static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
{
if (sk_X509_num(certs) == 1)
return 0;
return -1; /* let TSVN decide which certificate to use */
}
# ifdef OPENSSL_CAPIENG_DIALOG
/*
* More complex cert selection function, using standard function
* CryptUIDlgSelectCertificateFromStore() to produce a dialog box.
*/
/*
* Definitions which are in cryptuiapi.h but this is not present in older
* versions of headers.
*/
# ifndef CRYPTUI_SELECT_LOCATION_COLUMN
# define CRYPTUI_SELECT_LOCATION_COLUMN 0x000000010
# define CRYPTUI_SELECT_INTENDEDUSE_COLUMN 0x000000004
# endif
# define dlg_title L"TortoiseSVN SSL Client Certificate Selection"
# define dlg_prompt L"Select a certificate to use for authentication"
# define dlg_columns CRYPTUI_SELECT_LOCATION_COLUMN \
|CRYPTUI_SELECT_INTENDEDUSE_COLUMN
static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
{
X509 *x;
HCERTSTORE dstore;
PCCERT_CONTEXT cert;
CAPI_CTX *ctx;
CAPI_KEY *key;
HWND hwnd;
int i, idx = -1;
if (sk_X509_num(certs) == 1)
return 0;
ctx = ENGINE_get_ex_data(e, capi_idx);
/* Create an in memory store of certificates */
dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
if (!dstore) {
CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE);
capi_addlasterror();
goto err;
}
/* Add all certificates to store */
for (i = 0; i < sk_X509_num(certs); i++) {
x = sk_X509_value(certs, i);
key = X509_get_ex_data(x, cert_capi_idx);
if (!CertAddCertificateContextToStore(dstore, key->pcert,
CERT_STORE_ADD_NEW, NULL)) {
CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT);
capi_addlasterror();
goto err;
}
}
EnumWindows(FindWindoProc, (LPARAM)&hwnd);
if (!hwnd)
hwnd = GetForegroundWindow();
if (!hwnd)
hwnd = GetActiveWindow();
if (!hwnd && ctx->getconswindow)
hwnd = ctx->getconswindow();
/* Call dialog to select one */
cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt,
dlg_columns, 0, NULL);
/* Find matching cert from list */
if (cert) {
for (i = 0; i < sk_X509_num(certs); i++) {
x = sk_X509_value(certs, i);
key = X509_get_ex_data(x, cert_capi_idx);
if (CertCompareCertificate
(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo,
key->pcert->pCertInfo)) {
idx = i;
break;
}
}
}
err:
if (dstore)
CertCloseStore(dstore, 0);
return idx;
}
# endif
#else /* !__COMPILE_CAPIENG */
# include <openssl/engine.h>
# ifndef OPENSSL_NO_DYNAMIC_ENGINE
OPENSSL_EXPORT
int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
OPENSSL_EXPORT
int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
{
return 0;
}
IMPLEMENT_DYNAMIC_CHECK_FN()
# else
void engine_load_capi_int(void);
void engine_load_capi_int(void)
{
}
# endif
#endif