Yubico / yubihsm-shell

yubihsm-shell and libyubihsm
https://developers.yubico.com/yubihsm-shell/
Apache License 2.0
83 stars 50 forks source link

Using the YubiHSM with Android APKs and Bundles #329

Open zx2c4 opened 1 year ago

zx2c4 commented 1 year ago

Not sure where to post this, but in case you want to augment the documentation you have online for yubihsm-shell, today I got the YubiHSM2 working with Android's apksigner successfully (for WireGuard). I figure I should write down the details somewhere.

Android Signing with YubiHSM2

Initial key import

In a tmpfs:

$ openssl pkcs12 -in keystore.p12 -nocerts -out release.key -nodes
yubihsm> put asymmetric 0 my-key-id my-key-name 1 sign-pkcs,sign-pss release.key
$ openssl pkcs12 -in keystore.p12 -nokeys -out release.crt -nodes
yubihsm> set informat pem
yubihsm> put opaque 0 my-key-id my-key-name 1 sign-pkcs,sign-pss opaque-x509-certificate release.crt
$ shred -u keystore.p12 release.key release.crt

Replace my-key-id with the object ID and my-key-name with the object label.

There are various ways to generate keys or import keys or manage CSRs. The important nuance here is that both the private key and the opaque-x509-certificate public certificate need to be added with the same object ID.

Create various files

$ cat sun_yubihsm2_pkcs11.conf
name = yubihsm-pkcs11
library = /usr/lib64/pkcs11/yubihsm_pkcs11.so
attributes(*, CKO_PRIVATE_KEY, CKK_RSA) = {
  CKA_SIGN=true
}

$ cat yubihsm_pkcs11.conf
connector = yhusb://

Replace the connector field with a different URI, if you're using the YubiHSM2 over a network. Replace the library path with a different path if your distro's yubihsm-shell puts the yubihsm_pkcs11.so file elsewhere.

Make simple variable file to be sourced by scripts

$ cat apksigner-env.sh
export YUBIHSM_PKCS11_CONF="${BASH_SOURCE%/*}/yubihsm_pkcs11.conf"
export YUBIHSM_AUTH_PASS="0001$(pass Infra/yubihsm)"

# Java 17 doesn't allow using --provider-class otherwise.
# See: https://issuetracker.google.com/issues/277298127
APKSIGNER_JAVA_ARGS=(
    -J-add-opens=jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED
)

APKSIGNER_ARGS=(
    --ks NONE
    --ks-type PKCS11
    --provider-class sun.security.pkcs11.SunPKCS11
    --provider-arg "${BASH_SOURCE%/*}/sun_yubihsm2_pkcs11.conf"
    --ks-pass env:YUBIHSM_AUTH_PASS
    --ks-key-alias my-key-name
    --verbose
)

Replace 0001 if your YubiHSM2 auth key object is not of ID 0001. Replace the invocation of pass if you're managing passphrases differently. Replace my-key-name with the object label set earlier. Remove the -J-add-opens argument if you're running old java.

Sign files using apksigner from scripts

...
source ".../apksigner-env.sh"
apksigner "${APKSIGNER_JAVA_ARGS[@]}" sign "${APKSIGNER_ARGS[@]}" \
     --min-sdk-version "$minsdk" --in app-release.aab
apksigner "${APKSIGNER_JAVA_ARGS[@]}" sign "${APKSIGNER_ARGS[@]}" \
     --min-sdk-version "$minsdk" --in app-release-unsigned.apk --out app-release.apk
...
qpernil commented 1 year ago

Thank you for your contribution, this will be taken into consideration for future releases