Repository: rauc/rauc (C)

Issue:
code signing purpose check fails with OpenSSL 3.2
**Describe the bug**
Hi! :wave: 
When trying to package 1.11 for Arch Linux I ran the tests (`meson test -C build`).
Unfortunately the tests for `service` and `bundle` fail:

```
ninja: Entering directory `/build/rauc/src/build'
[1/1] Generating version.h with a custom command
 1/23 boot_raw_fallback OK               0.01s
 2/23 bootchooser       OK               1.79s
 3/23 checksum          OK               0.01s
 4/23 config_file       OK               0.16s
 5/23 context           OK               0.05s
 6/23 dm                OK               0.01s
 7/23 event_log         OK               0.06s
 8/23 hash_index        OK               0.01s
 9/23 manifest          OK               0.01s
10/23 signature         OK               0.03s
11/23 update_handler    OK               1.05s
12/23 utils             OK               0.01s
13/23 install           OK               0.53s
14/23 service           FAIL             0.14s   killed by signal 6 SIGABRT
>>> ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1 MALLOC_PERTURB_=62 /build/rauc/src/build/test/servic
e-test

15/23 status_file       OK               0.09s
16/23 bundle            FAIL             1.03s   killed by signal 6 SIGABRT
>>> MALLOC_PERTURB_=20 ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1 /build/rauc/src/build/test/bundle
-test

17/23 progress          OK               0.01s
18/23 slot              OK               0.01s
19/23 stats             OK               0.01s
20/23 network           OK               0.82s
21/23 nbd               OK               0.02s
22/23 boot_switch       OK               0.01s
23/23 rauc.t            OK               1.70s

Ok:                 21
Expected Fail:      0
Fail:               2
Unexpected Pass:    0
Skipped:            0
Timeout:            0

Full log written to /build/rauc/src/build/meson-logs/testlog.txt
```

**Background information**
1.11 from signed source tarball

**To Reproduce**
Steps to reproduce the behavior:
1. `arch-meson $pkgname-$pkgver build` (see https://gitlab.archlinux.org/archlinux/packaging/packages/meson/-/blob/97f7805dd7f5c9421e9b222d22a22a195c7a3c6d/arch-meson)
2. `meson compile -C build`
3. `meson test -C build`

**Expected behavior**
All tests pass.

**Logs**
Full meson test log: 
[testlog.txt](https://github.com/rauc/rauc/files/13758848/testlog.txt)

pkgctl build logs:
[rauc-1.11-1-x86_64-check.log](https://github.com/rauc/rauc/files/13758869/rauc-1.11-1-x86_64-check.log)
[rauc-1.11-1-x86_64-build.log](https://github.com/rauc/rauc/files/13758870/rauc-1.11-1-x86_64-build.log)

**Additional context**
n/a


Discussion: FWIW, the service test suite seems to fail because it can not start the systemd service via dbus (which I guess is to be expected when running in an systemd-nspawn container, that does not have that dbus/systemd service installed).

The bundle test failing seems to be due to a malformed signature:
```
Verify error: unsuitable certificate purpose (r_signature_error_quark, 16)
```
For the service check, please take a look at https://github.com/rauc/rauc/pull/1310.

Also, please note that the recommended way to run the tests is via ./qemu-test: https://github.com/rauc/rauc?tab=readme-ov-file#running-the-test-suite
Otherwise, large parts of the test suite cannot run due to missing privileges or emulated devices.

@dvzrv I can't reproduce the certificate purpose error on Debian, but have no experience with arch. Do you have a Dockerfile to prepare a build environment for RAUC somewhere? Or just the commands I'd need to install the build dependencies?
I ran into the `Verify error: unsuitable certificate purpose` error now. (In an actual test system, not the rauc tests) 

This seems to be caused by upgrading openssl to 3.2.0, which fails the same check even after downgrading back to rauc 1.10.1
The OpenSSL error may be caused by the fact that OpenSSL now defines 'codesign' itself: https://github.com/openssl/openssl/commit/178696d6020878361a088086243d56203e0beaa9

I guess this conflicts with our definition.
For now, we are going to rename our purpose check internally to `codesign-rauc`. That should keep the existing behavior and avoid the conflict with the OpenSSL definition.



Fix (patch):
diff --git a/src/config_file.c b/src/config_file.c
index 044a583b5..b93fe71ea 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -960,6 +960,12 @@ gboolean load_config(const gchar *filename, RaucConfig **config, GError **error)
 		g_propagate_error(error, ierror);
 		return FALSE;
 	}
+	/* Rewrite 'codesign' check-purpose to RAUC's internal 'codesign-rauc' check-purpose
+	 * to avoid conflicts with purpose definition from OpenSSL 3.2.0. */
+	if (g_strcmp0(c->keyring_check_purpose, "codesign") == 0) {
+		g_free(c->keyring_check_purpose);
+		c->keyring_check_purpose = g_strdup("codesign-rauc");
+	}
 
 	if (!check_remaining_keys(key_file, "keyring", &ierror)) {
 		g_propagate_error(error, ierror);
diff --git a/src/signature.c b/src/signature.c
index 7800b2ffd..30b8bc5cf 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -66,6 +66,14 @@ static int check_purpose_code_sign(const X509_PURPOSE *xp, const X509 *const_x,
 		return 0;
 	}
 
+	/* Despite we do not enforce it, CA browser forum notes a MUST on key usage.
+	 * (https://cabforum.org/wp-content/uploads/Baseline-Requirements-for-the-Issuance-and-Management-of-Code-Signing.v3.2.pdf
+	 * Section 7.1.2.3f)
+	 * For now, do not fail here, but at least emit a warning. */
+	if (!(ex_flags & EXFLAG_KUSAGE)) {
+		g_warning("Signer certificate should specify 'Key Usage' and mark it 'critical' to be fully CAB Forum compliant.");
+	}
+
 	return 1;
 }
 
@@ -96,7 +104,7 @@ gboolean signature_init(GError **error)
 	}
 
 	/* X509_TRUST_OBJECT_SIGN maps to the Code Signing ID (via OpenSSL's NID_code_sign) */
-	ret = X509_PURPOSE_add(id, X509_TRUST_OBJECT_SIGN, 0, check_purpose_code_sign, "Code signing", "codesign", NULL);
+	ret = X509_PURPOSE_add(id, X509_TRUST_OBJECT_SIGN, 0, check_purpose_code_sign, "Code signing", "codesign-rauc", NULL);
 	if (!ret) {
 		g_set_error(
 				error,