Building OpenSSL 1.1.1 and 3.0 for Windows CE

***Updated at Apr. 2022***
As well as 1.1.1, the newer version 3.0.x is also buildable for CE by adding a few fixes[^9]. It was found and confirmed to work by Asit. His contribution is now under a review process for merging to upstream. Hope it'll be approved.

---
This page introduces how I build OpenSSL 1.1.1 (only libraries, no command line application) for Windows CE. The build system and sources of OpenSSL have been changed dramatically in 1.1.0, we have to take some tweaks to build 1.1.1, though there is a good instruction[^1] for previous version.

I have confirmed that the build libraries works with our customized cURL based code. It can show a page available on only TLS1.3[^5].

# Requirements and prerequisite
Our build system is VisualStudio 2008 with WCE700 development environment on Windows7-64bit and target platform is ARMv4I. Perl execution environment is also needed.
Following source file are used. The version which is used here is in parentheses.

* wcecompat[^2] (`bad854b`)
* OpenSSL[^3] (`1.1.1b -` or `3.0.2 -`)

# Build wcecompat

1. Get wcecompat
1. Fix 2 known bugs as follow.
    * localtime() and gmtime()[^1]
        ```diff:src/time.c
          struct tm* localtime(const time_t* clock)
          …
        -     st_tm.tm_mon = stLocal.wMonth;
        +     st_tm.tm_mon = stLocal.wMonth - 1;
        -     st_tm.tm_year = stLocal.wYear;
        +     st_tm.tm_year = stLocal.wYear - 1900;
          …
          struct tm* gmtime(const time_t* clock)
          …
        -     st_tm.tm_mon = stUtc.wMonth;
        +     st_tm.tm_mon = stUtc.wMonth - 1;
        -     st_tm.tm_year = stUtc.wYear;
        +     st_tm.tm_year = stUtc.wYear - 1900;
        ```
    * Avoid infinite loop[^4]
        ```diff:src/wce211_string.c
          _CRTIMP char* __cdecl strrchr(const char* s, int c)
          {
              const char*    p = s + strlen(s) - 1;
              while (p >= s)
              {
                  if (*p == c)
                      return (char*)p;
        +         p -= 1;
              }
              return NULL;
          }
        ```

1. Modify headerfile
    * Add an alias, *_access* for *_wceaccess*
        ```diff:include/io.h
          #define access _wceaccess
        + #define _access _wceaccess
        ```
    * Add aliases for *stat* and *fstat* as below

        ```diff:include/sys/stat.h
        + #define _stat stat
        + #define _fstat fstat
          struct stat
          {
        ```

1. Set environmental variables
Replace `YOURSDKNAME` to your real sdk name.

    ```
    set OSVERSION=WCE700
    set PLATFORM=VC-CE
    set TARGETCPU=ARMV4I
    set LIB=C:\Program Files (x86)\Windows CE Tools\SDKs\YOURSDKNAME\Lib\ARMv4I;C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\ce\lib\armv4i;C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\lib
    set INCLUDE=C:\Program Files (x86)\Windows CE Tools\SDKs\YOURSDKNAME\Include\Armv4i
    set Path=C:\WINCE700\sdk\bin\i386\arm;C:\WINCE700\sdk\bin\i386;%Path%
    ```

1. Configure then build
On wcecompat top directory,
    ```bash
    > perl config.pl
    > nmake -f makefile
    ```

There should be _wcecompat.lib_ and _wcecompatex.lib_ in _lib_ directory if your build succeeds.

# Build OpenSSL
1. Get OpenSSL and extract
1. Apply a patch if needed
    * 1.1.1
        * (Before 1.1.1b) Apply the patch at https://github.com/aSoujyuTanaka/building_openssl-1.1.1_for_windowsce
        * (From 1.1.1c) No change is needed since my fix[^7] has been merged.
    * 3.0.x
        * Take the fix of OpenSSL pull request #18074[^9]

1. Set environmental variables
    * Replace `YOURSDKNAME` to your real sdk name.
    * Replace `the path of WCECOMPAT` to the actual one you build previously.
    ```
    set OSVERSION=WCE700
    set PLATFORM=VC-CE
    set TARGETCPU=ARMV4I
    set WCECOMPAT=C:\Users\tanaka\wcecompat
    set LIB=C:\Program Files (x86)\Windows CE Tools\SDKs\YOURSDKNAME\Lib\ARMV4I;C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\ce\lib\ARMV4I;C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\lib
    set INCLUDE=C:\Program Files (x86)\Windows CE Tools\SDKs\YOURSDKNAME\Include\ARMV4I;C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\ce\include
    set Path=C:\WINCE700\sdk\bin\i386\arm;C:\WINCE700\sdk\bin\i386;%Path%
    ```

1. Configure
    On OpenSSL top directory,
    ```bash
    > perl Configure no-idea no-mdc2 no-rc5 no-ssl3 no-weak-ssl-ciphers no-async no-engine VC-CE
    ```
    2 options are added on purpose. The reasons are as follows.
    * `no-async`: For lack of ConvertFiberToThread() in WinCE (used in _crypto/async/arch/async\_win.c_)
    * `no-engine`: For lack of CreatePipe() in WinCE (used in _engines/e\_dasync.c_)

1. Modify makefile as below (1.1.1b - 1.1.1g)
From 1.1.1h and 3.0.x, this step is no longer needed since another fix[^8] has been merged. Thanks to bjornl and Asit for helping me create the patch.
    ```diff:makefile
    - CFLAGS=/W3 /wd4090 /nologo /O1i
    + CFLAGS=/W3 /wd4090 /nologo /O1i -D_MSC_VER=1300
    @ ..
    - CNF_CPPFLAGS=-D_WIN32_WCE=700 -DUNDER_CE=700 -DWCE_PLATFORM_VC-CE -DARM -D_ARM_ -DARMV4I -QRarch4T -QRinterwork-return -D"OPENSSL_SYS_WIN32" -D"WIN32_LEAN_AND_MEAN" -D"UNICODE" -D"_UNICODE" -D"_CRT_SECURE_NO_DEPRECATE" -D"_WINSOCK_DEPRECATED_NO_WARNINGS" -D"NDEBUG" -I"\$(WCECOMPAT)/include"
    + CNF_CPPFLAGS=-D_WIN32_WCE=700 -DUNDER_CE=700 -DWCE_PLATFORM_VC-CE -DARM -D_ARM_ -DARMV4I -QRarch4T -QRinterwork-return -D"OPENSSL_SYS_WIN32" -D"WIN32_LEAN_AND_MEAN" -D"UNICODE" -D"_UNICODE" -D"_CRT_SECURE_NO_DEPRECATE" -D"_WINSOCK_DEPRECATED_NO_WARNINGS" -D"NDEBUG" -I$(WCECOMPAT)/include
    @ ..
    - CNF_EX_LIBS=3
    + CNF_EX_LIBS=ws2.lib $(WCECOMPAT)\lib\wcecompatex.lib corelibc.lib coredll.lib
    ```

1. Modify makefile for optimization if needed
If you are using WCE700 or above and target CPU is ARMv7 then you should replace any existence of `-QRarch4T` with `/QRarch7 /arch:VFPv3-D32 /QRfpe-` to take benefit of optimization for newer architecture[^6].

1. Build
    ```bash
    # For 1.1.1
    > nmake build_generated libcrypto-1_1.dll libssl-1_1.dll
    # For 3.0
    > nmake build_generated libcrypto-3.dll libssl-3.dll
    ```
Then you'll get the following artifacts.
  * libcrypto.lib
  * libcrypto-1_1.dll (or libcrypto-3.dll)
  * libssl.lib
  * libssl-1_1.dll  (or libssl-3.dll)

[^1]: [C++ UA Server SDK: Compiling OpenSSL for Windows CE](http://documentation.unified-automation.com/uasdkcpp/1.5.2/html/CompileOpenSSLCE.html)
[^2]: https://github.com/mauricek/wcecompat
[^3]: https://www.openssl.org/
[^4]: https://curl.haxx.se/mail/lib-2011-01/0219.html
[^5]: https://tls13.crypto.mozilla.org/
[^6]: http://rogeriodossantos.github.io/ARMv7-Performance/
[^7]: https://github.com/openssl/openssl/pull/8596
[^8]: https://github.com/openssl/openssl/pull/11526
[^9]: https://github.com/openssl/openssl/pull/18074/files