Skip to content

Commit bf703b9

Browse files
authored
Merge pull request #209 from cconlon/v1.10-android
Android test fixes and add Android FIPS Ready workflow
2 parents 4f89eda + 18cbeed commit bf703b9

18 files changed

Lines changed: 506 additions & 107 deletions

File tree

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
name: Android FIPS Ready Gradle Build and Test
2+
3+
on:
4+
push:
5+
branches: [ 'master', 'main', 'release/**' ]
6+
pull_request:
7+
branches: [ 'master' ]
8+
9+
concurrency:
10+
group: android-fips-${{ github.head_ref || github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
build_wolfcryptjni_fipsready:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Clone wolfcrypt-jni
18+
uses: actions/checkout@v4
19+
20+
# Free up disk space to prevent emulator from failing
21+
- name: Free up disk space
22+
run: |
23+
sudo rm -rf /usr/share/dotnet
24+
sudo rm -rf /usr/local/lib/android/sdk/ndk
25+
sudo rm -rf /opt/ghc
26+
sudo rm -rf /opt/hostedtoolcache/CodeQL
27+
sudo docker image prune --all --force
28+
df -h
29+
30+
# Get latest stable wolfSSL version for FIPS Ready download
31+
- name: Get latest wolfSSL stable version
32+
id: wolfssl-version
33+
run: |
34+
LATEST=$(curl -s -H "Authorization: token ${{ github.token }}" \
35+
"https://api.github.com/repos/wolfSSL/wolfssl/tags?per_page=100" | \
36+
jq -r '.[].name | select(endswith("-stable"))' | \
37+
sort -V | tail -1 | sed 's/^v//;s/-stable$//')
38+
if [ -z "$LATEST" ]; then
39+
echo "Failed to determine latest wolfSSL stable version" >&2
40+
exit 1
41+
fi
42+
echo "version=$LATEST" >> $GITHUB_OUTPUT
43+
echo "wolfSSL stable version: $LATEST"
44+
45+
# Cache wolfSSL FIPS Ready archive
46+
- name: Cache wolfSSL FIPS Ready archive
47+
uses: actions/cache@v4
48+
id: fips-cache
49+
with:
50+
path: wolfssl-fips-ready.zip
51+
key: wolfssl-fips-ready-${{ steps.wolfssl-version.outputs.version }}
52+
53+
# Download wolfSSL FIPS Ready if not cached
54+
- name: Download wolfSSL FIPS Ready
55+
if: steps.fips-cache.outputs.cache-hit != 'true'
56+
run: |
57+
VERSION="${{ steps.wolfssl-version.outputs.version }}"
58+
URL="https://www.wolfssl.com/wolfssl-${VERSION}-gplv3-fips-ready.zip"
59+
echo "Downloading: $URL"
60+
wget -q "$URL" -O wolfssl-fips-ready.zip
61+
62+
# Extract wolfSSL FIPS Ready to expected location
63+
- name: Extract wolfSSL FIPS Ready
64+
run: |
65+
unzip -q wolfssl-fips-ready.zip -d /tmp/wolfssl-fips-extract
66+
EXTRACTED_DIR=$(find /tmp/wolfssl-fips-extract -mindepth 1 -maxdepth 1 -type d | head -1)
67+
echo "Extracted directory: $EXTRACTED_DIR"
68+
ls "$EXTRACTED_DIR/wolfcrypt/src/" | head -5
69+
mv "$EXTRACTED_DIR" IDE/Android/app/src/main/cpp/wolfssl
70+
71+
# Configure CMakeLists.txt for FIPS Ready build
72+
- name: Configure for FIPS Ready
73+
run: |
74+
sed -i 's/set(WOLFSSL_PKG_TYPE "normal")/set(WOLFSSL_PKG_TYPE "fipsready")/' \
75+
IDE/Android/app/src/main/cpp/CMakeLists.txt
76+
grep 'WOLFSSL_PKG_TYPE' IDE/Android/app/src/main/cpp/CMakeLists.txt
77+
78+
# Patch MainActivity to auto-trigger WolfCryptProvider on launch,
79+
# so FIPS error callback fires and prints the expected hash to logcat
80+
# without needing a button press.
81+
- name: Patch MainActivity for auto FIPS hash detection
82+
run: |
83+
sed -i 's/button.setOnClickListener(buttonListener);/button.setOnClickListener(buttonListener);\n\n try { testFindProvider(null); } catch (Exception e) { e.printStackTrace(); }/' \
84+
IDE/Android/app/src/main/java/com/example/wolfssl/MainActivity.java
85+
86+
# Setup Java with Gradle caching
87+
- name: Setup java
88+
uses: actions/setup-java@v4
89+
with:
90+
distribution: 'zulu'
91+
java-version: '21'
92+
cache: 'gradle'
93+
94+
# Build all targets
95+
- name: Gradle Build (pass 1 - placeholder hash)
96+
run: cd IDE/Android && ./gradlew --build-cache assembleDebug assembleDebugUnitTest assembleDebugAndroidTest
97+
98+
# Enable KVM for hardware acceleration
99+
- name: Enable KVM
100+
run: |
101+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
102+
sudo udevadm control --reload-rules
103+
sudo udevadm trigger --name-match=kvm
104+
105+
# Cache AVD snapshot for faster emulator boot
106+
- name: AVD cache
107+
uses: actions/cache@v4
108+
id: avd-cache
109+
with:
110+
path: |
111+
~/.android/avd/*
112+
~/.android/adb*
113+
key: avd-wolfcryptjni-fips-30-x86_64-google_apis-v1
114+
115+
# Create AVD and generate snapshot for caching
116+
- name: Create AVD and generate snapshot
117+
if: steps.avd-cache.outputs.cache-hit != 'true'
118+
uses: reactivecircus/android-emulator-runner@v2.37.0
119+
with:
120+
api-level: 30
121+
arch: x86_64
122+
target: google_apis
123+
force-avd-creation: false
124+
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
125+
disable-animations: true
126+
script: echo "Generated AVD snapshot for caching"
127+
128+
# Launch app briefly to capture FIPS in-core hash from logcat.
129+
# The FIPS error callback prints the expected verifyCore hash on
130+
# startup if there is a mismatch.
131+
- name: Capture FIPS in-core hash
132+
id: fips-hash
133+
uses: reactivecircus/android-emulator-runner@v2.37.0
134+
timeout-minutes: 5
135+
with:
136+
api-level: 30
137+
arch: x86_64
138+
target: google_apis
139+
force-avd-creation: false
140+
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
141+
disable-animations: true
142+
script: |
143+
adb wait-for-device
144+
adb logcat -c
145+
cd IDE/Android && ./gradlew installDebug --no-daemon --no-watch-fs
146+
adb shell am start -W -n com.example.wolfssl/.MainActivity
147+
for i in 1 2 3 4 5 6; do sleep 5; adb logcat -d | grep -q 'hash = [A-Fa-f0-9]\{64\}' && break; echo "Waiting for FIPS hash ($i/6)..."; done
148+
adb logcat -d > /tmp/logcat_hash.txt 2>&1
149+
HASH=$(grep -o 'hash = [A-Fa-f0-9]\{64\}' /tmp/logcat_hash.txt | head -1 | sed 's/hash = //'); if [ -n "$HASH" ]; then echo "Captured FIPS hash: $HASH"; echo "hash=$HASH" >> $GITHUB_OUTPUT; else echo "No FIPS hash found in logcat, assuming existing hash is correct"; echo "hash=" >> $GITHUB_OUTPUT; fi
150+
151+
# Update FIPS hash in CMakeLists.txt and rebuild if needed
152+
- name: Rebuild with correct FIPS hash
153+
if: steps.fips-hash.outputs.hash != ''
154+
run: |
155+
HASH="${{ steps.fips-hash.outputs.hash }}"
156+
echo "Updating FIPS hash to: $HASH"
157+
sed -i "s/WOLFCRYPT_FIPS_CORE_HASH_VALUE=[A-Fa-f0-9]*/WOLFCRYPT_FIPS_CORE_HASH_VALUE=$HASH/g" \
158+
IDE/Android/app/src/main/cpp/CMakeLists.txt
159+
cd IDE/Android && ./gradlew --build-cache assembleDebug assembleDebugUnitTest assembleDebugAndroidTest
160+
161+
# Generate BKS KeyStore files for PKIX tests
162+
- name: Generate BKS KeyStore files
163+
run: |
164+
# Bouncy Castle version may need periodic updates
165+
BCPROV_JAR="bcprov-jdk18on-1.78.1.jar"
166+
BCPROV_URL="https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk18on/1.78.1/${BCPROV_JAR}"
167+
wget -q "$BCPROV_URL" -O "/tmp/${BCPROV_JAR}"
168+
wget -q "${BCPROV_URL}.sha256" -O "/tmp/${BCPROV_JAR}.sha256"
169+
(cd /tmp && echo "$(cat ${BCPROV_JAR}.sha256) ${BCPROV_JAR}" | sha256sum -c -)
170+
cd examples/certs && ./convert-to-bks.sh "/tmp/${BCPROV_JAR}"
171+
172+
# Run instrumented tests on Android emulator
173+
- name: Run Android Instrumented Tests
174+
uses: reactivecircus/android-emulator-runner@v2.37.0
175+
timeout-minutes: 15
176+
with:
177+
api-level: 30
178+
arch: x86_64
179+
target: google_apis
180+
force-avd-creation: false
181+
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
182+
disable-animations: true
183+
script: |
184+
adb wait-for-device
185+
adb shell mkdir -p /data/local/tmp/examples/certs/intermediate
186+
adb shell mkdir -p /data/local/tmp/examples/certs/rsapss
187+
adb shell mkdir -p /data/local/tmp/examples/certs/crl
188+
adb push ./examples/certs/ /data/local/tmp/examples/
189+
adb logcat -c
190+
cd IDE/Android && ./gradlew connectedDebugAndroidTest --no-daemon --no-watch-fs || { adb logcat -d > /tmp/logcat.txt 2>&1; echo "=== LOGCAT (errors) ==="; grep -i "exception\|error\|fatal" /tmp/logcat.txt || true; exit 1; }
191+
adb logcat -d > /tmp/logcat.txt 2>&1 || true
192+
# Clean up emulator processes. Safe to kill -9 since
193+
# -no-snapshot-save is used (no snapshot to corrupt).
194+
pgrep -f '[q]emu-system' | xargs -r kill -9 2>/dev/null || true
195+
pgrep -f '[c]rashpad' | xargs -r kill -9 2>/dev/null || true
196+
sleep 2
197+
198+
# Upload test reports even on failure
199+
- name: Upload Test Reports
200+
uses: actions/upload-artifact@v4
201+
if: always()
202+
timeout-minutes: 5
203+
with:
204+
name: android-fips-ready-test-reports
205+
path: |
206+
IDE/Android/app/build/reports/androidTests/
207+
/tmp/logcat.txt
208+
/tmp/logcat_hash.txt
209+
retention-days: 14

.github/workflows/windows-vs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66
ant_version:
77
description: 'Apache Ant version to use'
88
required: false
9-
default: '1.10.15'
9+
default: '1.10.16'
1010
type: string
1111
platform_toolset:
1212
description: 'Visual Studio platform toolset (auto-detect if not specified)'

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ wolfcrypt*.tar.gz
1919

2020
# Android
2121
IDE/Android/.idea/deploymentTargetDropDown.xml
22+
IDE/Android/.idea/vcs.xml
2223
IDE/Android/app/.cxx/
2324
IDE/Android/app/src/main/cpp/wolfssl
2425

IDE/Android/README.md

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,34 @@ del wolfssl
7575
mklink /D wolfssl ..\..\..\..\..\..\..\src\java\com\wolfssl\
7676
```
7777

78-
## 3. Push Certificate and KeyStore Files to Android Device
78+
## 3. Convert JKS KeyStore Files to BKS for Android Use
79+
80+
Android does not support JKS format KeyStores. Several JUnit tests
81+
require BKS format KeyStore files which must be converted from the existing
82+
JKS files.
83+
84+
To convert, you will need to download a Bouncy Castle provider JAR from the
85+
[Bouncy Castle website](https://www.bouncycastle.org/download/bouncy-castle-java/).
86+
Then run the conversion script from the `examples/certs` directory:
87+
88+
```
89+
cd examples/certs
90+
./convert-to-bks.sh <path/to/bcprov.jar>
91+
```
92+
93+
For example, when using `bcprov-jdk18on-1.78.1.jar`:
94+
95+
```
96+
cd examples/certs
97+
./convert-to-bks.sh ~/Downloads/bcprov-jdk18on-1.78.1.jar
98+
```
99+
100+
This will create the following BKS files needed by the Android tests:
101+
102+
- `ca-server-rsa-2048.bks`
103+
- `ca-server-ecc-256.bks`
104+
105+
## 4. Push Certificate and KeyStore Files to Android Device
79106

80107
Several JUnit tests require access to certificate and KeyStore files. These
81108
files are located in the `examples/certs` directory and must be pushed to
@@ -92,18 +119,20 @@ adb shell mkdir -p /data/local/tmp/examples/certs/crl
92119
adb push ./examples/certs/ /data/local/tmp/examples/
93120
```
94121

95-
This will push all certificate files, KeyStore files (.jks, .wks, .p12),
96-
and subdirectories (intermediate, rsapss, crl) needed by the JUnit tests.
122+
This will push all certificate files, KeyStore files (.jks, .wks, .bks,
123+
.p12), and subdirectories (intermediate, rsapss, crl) needed by the JUnit
124+
tests.
97125

98-
If this step is skipped, tests in the following classes will be skipped due
99-
to missing certificate files:
126+
If step 3 (BKS conversion) or this step is skipped, tests in the following
127+
classes will be skipped due to missing files:
100128

101-
- `WolfSSLKeyStoreTest`
129+
- `WolfCryptPKIXCertPathBuilderTest`
102130
- `WolfCryptPKIXCertPathValidatorTest`
103131
- `WolfCryptPKIXRevocationCheckerTest`
132+
- `WolfSSLKeyStoreTest`
104133
- `WolfSSLCertManagerOCSPTest`
105134

106-
## 4. Import and Build the Example Project with Android Studio
135+
## 5. Import and Build the Example Project with Android Studio
107136

108137
1) Open the Android Studio project by double clicking on the `Android` folder
109138
in wolfcrypt-jni/IDE/. Or, from inside Android Studio, open the `Android`

IDE/Android/app/build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ android {
1111
targetSdkVersion 33
1212
versionCode 1
1313
versionName "1.0"
14-
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1515
testInstrumentationRunnerArguments notClass: 'com.wolfssl.wolfcrypt.test.WolfCryptTestSuite,com.wolfssl.provider.jce.test.WolfJCETestSuite,com.wolfssl.wolfcrypt.test.fips.WolfCryptFipsTestSuite'
1616
externalNativeBuild {
1717
cmake {
@@ -42,10 +42,10 @@ android {
4242

4343
dependencies {
4444
implementation fileTree(dir: 'libs', include: ['*.jar'])
45-
implementation 'com.android.support:appcompat-v7:28.0.0'
46-
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
45+
implementation 'androidx.appcompat:appcompat:1.6.1'
46+
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
4747
testImplementation 'junit:junit:4.13.2'
4848
androidTestImplementation 'junit:junit:4.13.2'
49-
androidTestImplementation 'com.android.support.test:runner:1.0.2'
50-
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
49+
androidTestImplementation 'androidx.test:runner:1.5.2'
50+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
5151
}

IDE/Android/app/src/main/java/com/example/wolfssl/MainActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
package com.example.wolfssl;
2424

25-
import android.support.v7.app.AppCompatActivity;
25+
import androidx.appcompat.app.AppCompatActivity;
2626
import android.os.Bundle;
2727
import android.view.View;
2828
import android.widget.Button;

IDE/Android/app/src/main/res/layout/activity_main.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
2+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
44
xmlns:tools="http://schemas.android.com/tools"
55
android:layout_width="match_parent"
@@ -31,4 +31,4 @@
3131
app:layout_constraintTop_toTopOf="parent"
3232
app:layout_constraintVertical_bias="0.067" />
3333

34-
</android.support.constraint.ConstraintLayout>
34+
</androidx.constraintlayout.widget.ConstraintLayout>

IDE/Android/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
buildscript {
44
repositories {
55
google()
6-
jcenter()
6+
mavenCentral()
77

88
}
99
dependencies {
@@ -17,7 +17,7 @@ buildscript {
1717
allprojects {
1818
repositories {
1919
google()
20-
jcenter()
20+
mavenCentral()
2121
}
2222
gradle.projectsEvaluated {
2323
tasks.withType(JavaCompile) {

IDE/Android/gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# http://www.gradle.org/docs/current/userguide/build_environment.html
77
# Specifies the JVM arguments used for the daemon process.
88
# The setting is particularly useful for tweaking memory settings.
9+
android.useAndroidX=true
910
android.nonFinalResIds=false
1011
android.nonTransitiveRClass=false
1112
org.gradle.jvmargs=-Xmx1536m

0 commit comments

Comments
 (0)