1/03/2021

Android System App 권한

1. Android App Signature

Android App에 Signature 기능이 있는 것을 알아본게 된 이유가 System 권한을 가지고 실행하기 위해서 이를 알아보게되었다. 
왜냐하면, 일반적으로 만든 App들은 untrusted_app domain으로 SELinux에서 제한이 있어 매번 제대로 실행이 되지 않는 것을 해결해볼까 하고 생각이였다.
물론 SELinux를 허용모드로 하면 이문제는 이 부분이 다 필요가 없지만, 개발환경이 아닌 실제에서는 다르기때문에 이를 다시 생각하게되었다. 

물론 이 문제이외에도 permission에 관련된 문제가 있었으나, 그부분은 init.xxx.rc에서 강제로 했다. 

이부분은 OpenSSL의 인증서 Certificate(X.509)부분을 보면 쉽게이해가 가며, 간단히 보면, private key 와 public key의 사용으로 동작되는 것을 알 수 있다. 

암호화 기본개념 과 Cipher Suite

Android에서는 아래의 4종류의 Key가 있다고 하며 역할은 아래와 같다. 
  1. platform: a key for packages that are part of the core platform.
  2. shared: a key for things that are shared in the home/contacts process.
  3. media: a key for packages that are part of the media/download system.
  4. testkey: the default key to sign with if not otherwise specified.

https://boundarydevices.com/android-security-part-1-application-signatures-permissions/

상위과 같이 동작원리는 간단하다. 
Signing/Verfify 로 이를 쉽고 빠르게 검증하는 것이다. 


AOSP Source 기준으로 살펴보면 각 Key 위치와 Certificate 위치확인 

  • Default build system signs package 들과 testkey 아래 위치에 존재
$ ls build/target/product/security/
Android.mk  media.x509.pem    networkstack.x509.pem  platform.x509.pem  shared.pk8       testkey.pk8       verity_key  verity.x509.pem
media.pk8   networkstack.pk8  platform.pk8           README             shared.x509.pem  testkey.x509.pem  verity.pk8

  • Vendor NXP(Freescale)용 signs package 
$ ls device/fsl/common/security/
media.pk8       networkstack.pk8       platform.pk8       README             shared.pk8       testkey.pk8                 testkey_rsa4096.pem
media.x509.pem  networkstack.x509.pem  platform.x509.pem  rpmb_key_test.bin  shared.x509.pem  testkey_public_rsa4096.bin  testkey.x509.pem

$ grep -r  PRODUCT_DEFAULT_DEV_CERTIFICATE. .
./device/fsl/imx6sl/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx7d/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx6sx/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx6dq/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx7ulp/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx8m/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx8q/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \

$ cat ./device/fsl/imx8q/ProductConfigCommon.mk  // OVERWRITE 
...
PRODUCT_DEFAULT_DEV_CERTIFICATE := \
	device/fsl/common/security/testkey
...

$ cat ./device/fsl/imx8q/BoardConfig.mk  // AVB를 위한 RSA 비대칭키사용
.....
BOARD_AVB_ENABLE := true

BOARD_AVB_ALGORITHM := SHA256_RSA4096
# The testkey_rsa4096.pem is copied from external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_KEY_PATH := device/fsl/common/security/testkey_rsa4096.pem
.......

$ cat ./device/fsl/imx8q/mek_8q.mk  
.....
# Copy rpmb test key and AVB test public key
ifeq ($(PRODUCT_IMX_TRUSTY),true)
PRODUCT_COPY_FILES += \
    device/fsl/common/security/rpmb_key_test.bin:rpmb_key_test.bin \
    device/fsl/common/security/testkey_public_rsa4096.bin:testkey_public_rsa4096.bin
endif
.....

PRODUCT_DEFAULT_DEV_CERTIFICATE 에 의해 overwrite가 가능하다고 하니, 상위와 같이 검색  

platform/shared/media/testkey 생성부터 인증관련내용

1.1 ASOP Source에서 platform Key 추출 

  • ASOP Default Platform Key 추출 
두개의 password는 android로 설정 했으며, key alias는 androiddebugkey로 설정 
$ mkdir mytest1
$ cp build/target/product/security/platform.pk8 mytest1/
$ cp build/target/product/security/platform.x509.pem mytest1/

$ cd mytest1

//PKCS#08:  Private-Key Information Syntax Standard 로 아래와 같이 변경 (DER) platform.pem로 생성 
//PKCS#12:  Personal Information Exchange Syntax Standard 로 platform.x509.pem을 platform.p12로 변경  Private KEY는 platform.pem이용하고 설정값  

$ openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem 
$ openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.p12 -password pass:android -name androiddebugkey 
$ keytool -importkeystore -deststorepass android -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass android  

$ ls 
platform.jks  platform.p12  platform.pem  platform.pk8  platform.x509.pem

PKCSx(Public Key Cryptography Standards)
  1. PKCS_12:공개키 인증서 교환문법 표준
  2. PKCS_08:개인키 정보 문법 표준 


  • NXP용 Platform Key 추출 
두개의 password는 android로 설정 했으며, key alias는 androiddebugkey로 설정 
$ mkdir mytest2
$ cp device/fsl/common/security/platform.pk8 mytest2/
$ cp device/fsl/common/security/platform.x509.pem mytest2/

$ cd mytest2

$ openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem 
$ openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.p12 -password pass:android -name androiddebugkey 
$ keytool -importkeystore -deststorepass android -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass android 

$ ls 
platform.jks  platform.p12  platform.pem  platform.pk8  platform.x509.pem

Platform Key 추출


Platform Key 관련링크들  

2. App 에 System App 권한부여  

상위에서도 설명했지만, 기본 App은 untruested_app으로 실행되기 때문에 SELinux와 Permission 문제가 발생해서 이부분을 system 권한으로 변경하도록 실행 

  • Androidmanifest.XML 에서 system 권한 부여
Java에서 현재 root는 안된다고 하는데, 과거에는 된 것 같음 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.beep"
    android:sharedUserId="android.uid.system" >

  • ASOP에서 NXP platform.jks 추출 후 Android Studio 에서 Sign 방법 
Android Studio -> File -> Project Structure -> Signing Config


or 

Android Studio -> Build -> Generate Signed Bundle/APK -> APK

상위처럼 하면, 구지 build.gradle를 직접 수정하지 하지 않해도 되지만, debug 와 release를 구분해서 넣어주자.  


기본 SELinux Domain untrusted_app
[12387.628007] type=1400 audit(1611554077.764:163): avc: denied { read } for comm="om.example.beep" name="duty_cycle" dev="sysfs" ino=37724 scontext=u:r:untrusted_app:s0:c101,c256,c512,c768 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1 app=com.example.beep
바뀔 SELInux Domain system_app
[14697.359731] type=1400 audit(1611556387.500:167): avc: denied { read } for comm="om.example.beep" name="duty_cycle" dev="sysfs" ino=37724 scontext=u:r:system_app:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1

현재 permission 과 권한도 system으로 변경했지만 SELinux에서 거부되는 것은 현재 sysfs 때문이라고 생각이 된다. 

매번 Build Clean 후 다시 실행했으며, 만약 INSTALL_FAILED_SHARED_USER_INCOMPATIBLE 에러가 계속나면, 나의 경우, 상위 system 설정 후 Sign이 맞지않아 생겼다.
NXP용 platform key를 사용해야 문제가 없었음  

  • adb shell or serial 에서 package 설치확인 
Terminal에서  package 설치확인 
$ su
#
# pm list packages | grep <package>

# pm uninstall <package>


2.1 signapk.jar를 이용한 Sign 방법 

아직 해보지 못했으며, 관련부분만 현재 검색했음 

  • Android App Sign 
apk 생성후 이를 ASOP에서 직접 signapk.jar를 이용하여 sign하는 방법 
$ find . -name signapk.jar
./out/host/linux-x86/framework/signapk.jar
./out/soong/host/linux-x86/framework/signapk.jar
./out/soong/.intermediates/build/make/tools/signapk/signapk/linux_glibc_common/combined/signapk.jar
./out/soong/.intermediates/build/make/tools/signapk/signapk/linux_glibc_common/javac/signapk.jar
./prebuilts/sdk/tools/lib/signapk.jar

$ mkdir mytest
$ cp my_nosign.apk   mytest/              // my app 
$ cp build/target/product/security/platform.x509.pem  mytest/
$ cp build/target/product/security/platform.pk8   mytest/
$ cp out/host/linux-x86/framework/signapk.jar  mytest/
$ cd mytest

$ java -jar signapk.jar platform.x509.pem platform.pk8 my_nosign.apk my_sign.apk        // signing apk 
$ ls my_sign.apk