From e1f6410c5ecdb919692097999030467f30a95745 Mon Sep 17 00:00:00 2001 From: lihehe Date: Mon, 11 Mar 2024 22:07:23 +0800 Subject: [PATCH] verify cert chain from local code sign SA Signed-off-by: lihehe Change-Id: Ia7697c8a8844a1047ba8b94c91e53638a8fa7c67 --- interfaces/innerkits/common/include/errcode.h | 3 +- interfaces/innerkits/local_code_sign/BUILD.gn | 7 +- .../include/local_code_sign_interface.h | 4 +- .../include/local_code_sign_proxy.h | 4 +- .../src/local_code_sign_client.cpp | 13 +- .../src/local_code_sign_proxy.cpp | 11 +- services/key_enable/src/key_enable.rs | 34 +-- .../utils/src/local_code_sign_utils.cpp | 8 +- services/local_code_sign/BUILD.gn | 12 + .../OpenHarmony/trusted_attest_root_ca.cer | 24 ++ .../config/trusted_attest_root_ca.cer | 45 +++ .../include/local_code_sign_service.h | 4 +- .../local_code_sign/include/local_sign_key.h | 54 +--- .../src/local_code_sign_service.cpp | 13 +- .../src/local_code_sign_stub.cpp | 15 +- .../local_code_sign/src/local_sign_key.cpp | 46 ++- test/fuzztest/BUILD.gn | 43 +-- .../initlocalcertificate_fuzzer/BUILD.gn | 72 +++++ .../initlocalcertificate_fuzzer/corpus/init | 14 + .../initlocalcertificatestub_fuzzer.cpp | 73 +++++ .../initlocalcertificatestub_fuzzer.h | 21 ++ .../initlocalcertificate_fuzzer/project.xml | 25 ++ test/unittest/utils/src/xpm_common.cpp | 2 +- utils/include/cert_utils.h | 12 +- utils/include/huks_attest_verifier.h | 29 ++ utils/include/huks_param_set.h | 72 +++++ utils/include/openssl_utils.h | 7 +- utils/include/pkcs7_data.h | 7 +- utils/include/sign_key.h | 1 - utils/include/signer_info.h | 14 +- utils/src/cert_utils.cpp | 118 ++++++- utils/src/huks_attest_verifier.cpp | 288 ++++++++++++++++++ utils/src/openssl_utils.cpp | 13 + utils/src/pkcs7_data.cpp | 5 +- utils/src/signer_info.cpp | 26 +- 35 files changed, 975 insertions(+), 164 deletions(-) create mode 100644 services/local_code_sign/config/OpenHarmony/trusted_attest_root_ca.cer create mode 100644 services/local_code_sign/config/trusted_attest_root_ca.cer create mode 100644 test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/BUILD.gn create mode 100644 test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/corpus/init create mode 100644 test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/initlocalcertificatestub_fuzzer.cpp create mode 100644 test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/initlocalcertificatestub_fuzzer.h create mode 100644 test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/project.xml create mode 100644 utils/include/huks_attest_verifier.h create mode 100644 utils/include/huks_param_set.h create mode 100644 utils/src/huks_attest_verifier.cpp diff --git a/interfaces/innerkits/common/include/errcode.h b/interfaces/innerkits/common/include/errcode.h index 0dd77c2..474c409 100644 --- a/interfaces/innerkits/common/include/errcode.h +++ b/interfaces/innerkits/common/include/errcode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -40,6 +40,7 @@ enum SignErrCode { CS_ERR_COMPUTE_DIGEST = -0x204, CS_ERR_NO_OWNER_ID = -0x205, CS_ERR_INIT_LOCAL_CERT = -0x206, + CS_ERR_VERIFY_CERT = -0x207 }; enum OpenSSLErrCode { diff --git a/interfaces/innerkits/local_code_sign/BUILD.gn b/interfaces/innerkits/local_code_sign/BUILD.gn index 5c5a55a..8aaa9d3 100644 --- a/interfaces/innerkits/local_code_sign/BUILD.gn +++ b/interfaces/innerkits/local_code_sign/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Huawei Device Co., Ltd. +# Copyright (c) 2023-2024 Huawei Device Co., Ltd. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -26,6 +26,9 @@ ohos_shared_library("liblocal_code_sign_sdk") { } branch_protector_ret = "pac_ret" sources = [ + "${code_signature_root_dir}/utils/src/cert_utils.cpp", + "${code_signature_root_dir}/utils/src/huks_attest_verifier.cpp", + "${code_signature_root_dir}/utils/src/openssl_utils.cpp", "src/local_code_sign_client.cpp", "src/local_code_sign_kit.cpp", "src/local_code_sign_load_callback.cpp", @@ -42,7 +45,9 @@ ohos_shared_library("liblocal_code_sign_sdk") { "c_utils:utils", "hilog:libhilog", "hisysevent:libhisysevent", + "huks:libhukssdk", "ipc:ipc_core", + "openssl:libcrypto_shared", "safwk:system_ability_fwk", "samgr:samgr_proxy", ] diff --git a/interfaces/innerkits/local_code_sign/include/local_code_sign_interface.h b/interfaces/innerkits/local_code_sign/include/local_code_sign_interface.h index 2deb584..c6dbba2 100644 --- a/interfaces/innerkits/local_code_sign/include/local_code_sign_interface.h +++ b/interfaces/innerkits/local_code_sign/include/local_code_sign_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -29,7 +29,7 @@ constexpr int LOCAL_CODE_SIGN_SA_ID = 3507; class LocalCodeSignInterface : public OHOS::IRemoteBroker { public: DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.Security.LocalCodeSignInterface"); - virtual int32_t InitLocalCertificate(ByteBuffer &cert) = 0; + virtual int32_t InitLocalCertificate(const ByteBuffer &challenge, ByteBuffer &cert) = 0; virtual int32_t SignLocalCode(const std::string &ownerID, const std::string &filePath, ByteBuffer &signature) = 0; }; } diff --git a/interfaces/innerkits/local_code_sign/include/local_code_sign_proxy.h b/interfaces/innerkits/local_code_sign/include/local_code_sign_proxy.h index 12b56c5..26283c2 100644 --- a/interfaces/innerkits/local_code_sign/include/local_code_sign_proxy.h +++ b/interfaces/innerkits/local_code_sign/include/local_code_sign_proxy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -28,7 +28,7 @@ public: explicit LocalCodeSignProxy(const sptr &impl) : IRemoteProxy(impl) {} ~LocalCodeSignProxy() {} - int32_t InitLocalCertificate(ByteBuffer &cert) override; + int32_t InitLocalCertificate(const ByteBuffer &challenge, ByteBuffer &cert) override; int32_t SignLocalCode(const std::string &ownerID, const std::string &filePath, ByteBuffer &signature) override; private: static inline BrokerDelegator delegator_; diff --git a/interfaces/innerkits/local_code_sign/src/local_code_sign_client.cpp b/interfaces/innerkits/local_code_sign/src/local_code_sign_client.cpp index 3c4aee5..a950468 100644 --- a/interfaces/innerkits/local_code_sign/src/local_code_sign_client.cpp +++ b/interfaces/innerkits/local_code_sign/src/local_code_sign_client.cpp @@ -15,7 +15,10 @@ #include "local_code_sign_client.h" #include + +#include "cert_utils.h" #include "cs_hisysevent.h" +#include "huks_attest_verifier.h" #include "local_code_sign_proxy.h" #include "local_code_sign_load_callback.h" #include "log.h" @@ -131,12 +134,18 @@ int32_t LocalCodeSignClient::InitLocalCertificate(ByteBuffer &cert) if (localCodeSignProxy_ == nullptr) { return CS_ERR_SA_GET_PROXY; } - int32_t ret = localCodeSignProxy_->InitLocalCertificate(cert); + ByteBuffer certChainBuffer; + std::unique_ptr challenge = GetRandomChallenge(); + int32_t ret = localCodeSignProxy_->InitLocalCertificate(*challenge, certChainBuffer); if (ret != CS_SUCCESS) { LOG_ERROR("InitLocalCertificate err, error code = %{public}d", ret); return ret; } - return CS_SUCCESS; + + if (!GetVerifiedCert(certChainBuffer, *challenge, cert)) { + ret = CS_ERR_VERIFY_CERT; + } + return ret; } int32_t LocalCodeSignClient::SignLocalCode(const std::string &ownerID, const std::string &path, ByteBuffer &signature) diff --git a/interfaces/innerkits/local_code_sign/src/local_code_sign_proxy.cpp b/interfaces/innerkits/local_code_sign/src/local_code_sign_proxy.cpp index aa26506..c74b369 100644 --- a/interfaces/innerkits/local_code_sign/src/local_code_sign_proxy.cpp +++ b/interfaces/innerkits/local_code_sign/src/local_code_sign_proxy.cpp @@ -22,9 +22,8 @@ namespace OHOS { namespace Security { namespace CodeSign { -constexpr uint32_t MAX_REPLY_BUFFER_SIZE = 65536; -int32_t LocalCodeSignProxy::InitLocalCertificate(ByteBuffer &cert) +int32_t LocalCodeSignProxy::InitLocalCertificate(const ByteBuffer &challenge, ByteBuffer &cert) { MessageParcel data; MessageParcel reply; @@ -36,6 +35,12 @@ int32_t LocalCodeSignProxy::InitLocalCertificate(ByteBuffer &cert) if (!data.WriteInterfaceToken(GetDescriptor())) { return CS_ERR_IPC_WRITE_DATA; } + if (!data.WriteUint32(challenge.GetSize())) { + return CS_ERR_IPC_WRITE_DATA; + } + if (!data.WriteBuffer(challenge.GetBuffer(), challenge.GetSize())) { + return CS_ERR_IPC_WRITE_DATA; + } if (remote->SendRequest(static_cast(LocalCodeSignInterfaceCode::INIT_LOCAL_CERTIFICATE), data, reply, option) != NO_ERROR) { return CS_ERR_IPC_MSG_INVALID; @@ -88,7 +93,7 @@ int32_t LocalCodeSignProxy::ReadResultFromReply(MessageParcel &reply, ByteBuffer if (!reply.ReadUint32(size)) { return CS_ERR_IPC_READ_DATA; } - if (size > MAX_REPLY_BUFFER_SIZE) { + if (size > reply.GetReadableBytes()) { LOG_ERROR("Invalid reply data size."); return CS_ERR_IPC_MSG_INVALID; } diff --git a/services/key_enable/src/key_enable.rs b/services/key_enable/src/key_enable.rs index 87c49bb..37fbd1e 100644 --- a/services/key_enable/src/key_enable.rs +++ b/services/key_enable/src/key_enable.rs @@ -24,7 +24,6 @@ use std::fs::File; use std::io::{BufRead, BufReader}; use std::option::Option; use std::ptr; -use std::thread::sleep_ms; const LOG_LABEL: HiLogLabel = HiLogLabel { log_type: LogType::LogCore, @@ -40,10 +39,6 @@ const LOCAL_KEY_NAME: &str = "local_key"; const CODE_SIGN_KEY_NAME_PREFIX: &str = "fs_verity_key"; const SUCCESS: i32 = 0; -// retry to get local cert -const LOCAL_CERT_MAX_RETRY_TIMES: i32 = 5; -const SLEEP_MILLI_SECONDS: u32 = 50; - type KeySerial = i32; extern "C" { @@ -72,8 +67,10 @@ fn get_local_key() -> Option> { let mut cert_size = CERT_DATA_MAX_SIZE; let mut cert_data = Vec::with_capacity(cert_size); let pcert = cert_data.as_mut_ptr(); + unsafe { - if InitLocalCertificate(pcert, &mut cert_size) == 0 { + let ret = InitLocalCertificate(pcert, &mut cert_size); + if ret == 0 { cert_data.set_len(cert_size); Some(cert_data) } else { @@ -166,27 +163,12 @@ fn enable_trusted_keys(key_id: KeySerial, root_cert: &PemCollection) { // enable local key from local code sign SA fn enable_local_key(key_id: KeySerial) { - let mut times = 0; - let cert_data = loop { - match get_local_key() { - Some(key) => { - break key; - } - None => { - error!(LOG_LABEL, "Get local key failed, may try again."); - } - } - times += 1; - if times == LOCAL_CERT_MAX_RETRY_TIMES { - error!(LOG_LABEL, "Local key is not avaliable."); - return; + if let Some(cert_data) = get_local_key() { + let ret = enable_key(key_id, LOCAL_KEY_NAME, &cert_data); + if ret < 0 { + cs_hisysevent::report_add_key_err("local_key", ret); + error!(LOG_LABEL, "Enable local key failed"); } - sleep_ms(SLEEP_MILLI_SECONDS); - }; - let ret = enable_key(key_id, LOCAL_KEY_NAME, &cert_data); - if ret < 0 { - cs_hisysevent::report_add_key_err("local_key", ret); - error!(LOG_LABEL, "Enable local key failed"); } } diff --git a/services/key_enable/utils/src/local_code_sign_utils.cpp b/services/key_enable/utils/src/local_code_sign_utils.cpp index 8cb2b40..db6cc55 100644 --- a/services/key_enable/utils/src/local_code_sign_utils.cpp +++ b/services/key_enable/utils/src/local_code_sign_utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,12 +15,12 @@ #include "local_code_sign_utils.h" +#include #include #include "byte_buffer.h" #include "local_code_sign_kit.h" #include "log.h" -#include "securec.h" #include "thread_ex.h" using namespace OHOS::Security::CodeSign; @@ -28,8 +28,8 @@ using namespace OHOS::Security::CodeSign; namespace OHOS { namespace Security { namespace CodeSign { -constexpr uint32_t INIT_LOCAL_CERT_TIMEOUT_MS = 300 * 1000; -constexpr uint32_t INIT_LOCAL_CERT_SLEEP_US = 1000 * 1000; +constexpr uint32_t INIT_LOCAL_CERT_TIMEOUT_MS = 300 * 1000; // 5min +constexpr uint32_t INIT_LOCAL_CERT_SLEEP_US = 1000 * 1000; // 1s const std::string INIT_LOCAL_CERT_THREAD_NAME = "init_local_cert"; static std::condition_variable g_condition; diff --git a/services/local_code_sign/BUILD.gn b/services/local_code_sign/BUILD.gn index 0a26392..acf304b 100644 --- a/services/local_code_sign/BUILD.gn +++ b/services/local_code_sign/BUILD.gn @@ -66,6 +66,7 @@ group("local_code_sign_configs") { deps = [ ":local_code_sign.cfg", ":local_code_sign_sa_profile", + ":trusted_attest_root_ca", ] } @@ -80,3 +81,14 @@ ohos_sa_profile("local_code_sign_sa_profile") { sources = [ "sa_profile/3507.json" ] part_name = "code_signature" } + +ohos_prebuilt_etc("trusted_attest_root_ca") { + if (!code_signature_support_oh_code_sign) { + source = "config/OpenHarmony/trusted_attest_root_ca.cer" + } else { + source = "config/trusted_attest_root_ca.cer" + } + part_name = "code_signature" + subsystem_name = "security" + relative_install_dir = "security" +} diff --git a/services/local_code_sign/config/OpenHarmony/trusted_attest_root_ca.cer b/services/local_code_sign/config/OpenHarmony/trusted_attest_root_ca.cer new file mode 100644 index 0000000..1a266e3 --- /dev/null +++ b/services/local_code_sign/config/OpenHarmony/trusted_attest_root_ca.cer @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEBzCCAu+gAwIBAgIUSvxlT2cTI5rj67Ng5lqQ76peRYswDQYJKoZIhvcNAQEL +BQAwgZIxCzAJBgNVBAYTAkNOMRMwEQYDVQQIDApoZWxsb3dvcmxkMRMwEQYDVQQH +DApoZWxsb3dvcmxkMRMwEQYDVQQKDApoZWxsb3dvcmxkMRMwEQYDVQQLDApoZWxs +b3dvcmxkMRQwEgYDVQQDDAtoZWxsb3dvcmxkMTEZMBcGCSqGSIb3DQEJARYKaGVs +bG93b3JsZDAeFw0yMjAxMjIwOTIxNDRaFw0zMjAxMjAwOTIxNDRaMIGSMQswCQYD +VQQGEwJDTjETMBEGA1UECAwKaGVsbG93b3JsZDETMBEGA1UEBwwKaGVsbG93b3Js +ZDETMBEGA1UECgwKaGVsbG93b3JsZDETMBEGA1UECwwKaGVsbG93b3JsZDEUMBIG +A1UEAwwLaGVsbG93b3JsZDExGTAXBgkqhkiG9w0BCQEWCmhlbGxvd29ybGQwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnf9wv+5yjFTjR4iEFx792ROxA +J3TCbALv68l+xAEbYLY8Uen3Zx9i55iwm6uJrEK3qhVyf3jDPBZA2XC8ta1TDG01 +i8BsVwl5l7EZXvtt0t0McP7AwHYQRr2r+oSHzyox9In+39uo0ZbUWVO8MoewubLD +0TyYvmakol0/mkOWan3LU9BYrjayQHmwfIr9J4aGdfTrguVKrTcs/+eVJycOmC3v +5kQg4taE0UxJw+sISyMcVcXgFW8qlcCtYIqwMvyi/ZEfE/DvHHtsRkGKEYkk4LAh +hqtKqYZJK+hB1gAEZ/6Ox8ryoV9Q7H2LdkwBCrzhLFY8ZUlKyddXqpNyAnnHAgMB +AAGjUzBRMB0GA1UdDgQWBBSad3PlRaRpQv6/1IjwqM6B9VHIDDAfBgNVHSMEGDAW +gBSad3PlRaRpQv6/1IjwqM6B9VHIDDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQA0G+qd52/lic6XrlpaZvAf1jI75fZARdAE0RM9SX1ouYF/AjNu +8atrSQOyX4xz0Dz82CfCil/pazEiyagChSe249SRXxUXUD6v2yVuXjjGJdZjP3S4 +T6iMq34Zg4lNxaPD/dW5hHbIKX/NFwzMzp5guc+tgTLVZRILLvQ2VgO9E9ZC3fvJ +5dBKnOHyRR8jE1b7wZ5Bm635FqoMI4GdJ9doqUketbWmuxFaNxNOl70oF4Nqai8u +ogBCx/4P/K+IhGWiTwIT/alLtjHF+kHTS6aw4wxKr6oLj8U0nHfBNWUDLSsMS91p +xuSX+C1JOt0mtwnTPe7FCSHNc0EFwfHbjjp/ +-----END CERTIFICATE----- \ No newline at end of file diff --git a/services/local_code_sign/config/trusted_attest_root_ca.cer b/services/local_code_sign/config/trusted_attest_root_ca.cer new file mode 100644 index 0000000..f16eada --- /dev/null +++ b/services/local_code_sign/config/trusted_attest_root_ca.cer @@ -0,0 +1,45 @@ +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIIYsLLTehAXpYwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UE +BhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEbMBkG +A1UEAwwSSHVhd2VpIENCRyBSb290IENBMB4XDTE3MDgyMTEwNTYyN1oXDTQyMDgx +NTEwNTYyN1owUDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE +CwwKSHVhd2VpIENCRzEbMBkGA1UEAwwSSHVhd2VpIENCRyBSb290IENBMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1OyKm3Ig/6eibB7Uz2o93UqGk2M7 +84WdfF8mvffvu218d61G5M3Px54E3kefUTk5Ky1ywHvw7Rp9KDuYv7ktaHkk+yr5 +9Ihseu3a7iM/C6SnMSGt+LfB/Bcob9Abw95EigXQ4yQddX9hbNrin3AwZw8wMjEI +SYYDo5GuYDL0NbAiYg2Y5GpfYIqRzoi6GqDz+evLrsl20kJeCEPgJZN4Jg00Iq9k +++EKOZ5Jc/Zx22ZUgKpdwKABkvzshEgG6WWUPB+gosOiLv++inu/9blDpEzQZhjZ +9WVHpURHDK1YlCvubVAMhDpnbqNHZ0AxlPletdoyugrH/OLKl5inhMXNj3Re7Hl8 +WsBWLUKp6sXFf0dvSFzqnr2jkhicS+K2IYZnjghC9cOBRO8fnkonh0EBt0evjUIK +r5ClbCKioBX8JU+d4ldtWOpp2FlxeFTLreDJ5ZBU4//bQpTwYMt7gwMK+MO5Wtok +Ux3UF98Z6GdUgbl6nBjBe82c7oIQXhHGHPnURQO7DDPgyVnNOnTPIkmiHJh/e3vk +VhiZNHFCCLTip6GoJVrLxwb9i4q+d0thw4doxVJ5NB9OfDMV64/ybJgpf7m3Ld2y +E0gsf1prrRlDFDXjlYyqqpf1l9Y0u3ctXo7UpXMgbyDEpUQhq3a7txZQO/17luTD +oA6Tz1ADavvBwHkCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFKrE03lH6G4ja+/wqWwicz16GWmhMA0GCSqGSIb3DQEB +CwUAA4ICAQC1d3TMB+VHZdGrWJbfaBShFNiCTN/MceSHOpzBn6JumQP4N7mxCOwd +RSsGKQxV2NPH7LTXWNhUvUw5Sek96FWx/+Oa7jsj3WNAVtmS3zKpCQ5iGb08WIRO +cFnx3oUQ5rcO8r/lUk7Q2cN0E+rF4xsdQrH9k2cd3kAXZXBjfxfKPJTdPy1XnZR/ +h8H5EwEK5DWjSzK1wKd3G/Fxdm3E23pcr4FZgdYdOlFSiqW2TJ3Qe6lF4GOKOOyd +WHkpu54ieTsqoYcuMKnKMjT2SLNNgv9Gu5ipaG8Olz6g9C7Htp943lmK/1Vtnhgg +pL3rDTsFX/+ehk7OtxuNzRMD9lXUtEfok7f8XB0dcL4ZjnEhDmp5QZqC1kMubHQt +QnTauEiv0YkSGOwJAUZpK1PIff5GgxXYfaHfBC6Op4q02ppl5Q3URl7XIjYLjvs9 +t4S9xPe8tb6416V2fe1dZ62vOXMMKHkZjVihh+IceYpJYHuyfKoYJyahLOQXZykG +K5iPAEEtq3HPfMVF43RKHOwfhrAH5KwelUA/0EkcR4Gzth1MKEqojdnYNemkkSy7 +aNPPT4LEm5R7sV6vG1CjwbgvQrWCgc4nMb8ngdfnVF7Ydqjqi9SAqUzIk4+Uf0ZY ++6RY5IcHdCaiPaWIE1xURQ8B0DRUURsQwXdjZhgLN/DKJpCl5aCCxg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICGjCCAaGgAwIBAgIIShhpn519jNAwCgYIKoZIzj0EAwMwUzELMAkGA1UEBhMC +Q04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEeMBwGA1UE +AwwVSHVhd2VpIENCRyBSb290IENBIEcyMB4XDTIwMDMxNjAzMDQzOVoXDTQ5MDMx +NjAzMDQzOVowUzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE +CwwKSHVhd2VpIENCRzEeMBwGA1UEAwwVSHVhd2VpIENCRyBSb290IENBIEcyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEWidkGnDSOw3/HE2y2GHl+fpWBIa5S+IlnNrs +GUvwC1I2QWvtqCHWmwFlFK95zKXiM8s9yV3VVXh7ivN8ZJO3SC5N1TCrvB2lpHMB +wcz4DA0kgHCMm/wDec6kOHx1xvCRo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUo45a9Vq8cYwqaiVyfkiS4pLcIAAwCgYIKoZI +zj0EAwMDZwAwZAIwMypeB7P0IbY7c6gpWcClhRznOJFj8uavrNu2PIoz9KIqr3jn +BlBHJs0myI7ntYpEAjBbm8eDMZY5zq5iMZUC6H7UzYSix4Uy1YlsLVV738PtKP9h +FTjgDHctXJlC5L7+ZDY= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/services/local_code_sign/include/local_code_sign_service.h b/services/local_code_sign/include/local_code_sign_service.h index f665f67..170e602 100644 --- a/services/local_code_sign/include/local_code_sign_service.h +++ b/services/local_code_sign/include/local_code_sign_service.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -33,7 +33,7 @@ public: void OnStart() override; void OnStop() override; - int32_t InitLocalCertificate(ByteBuffer &cert) override; + int32_t InitLocalCertificate(const ByteBuffer &challenge, ByteBuffer &cert) override; int32_t SignLocalCode(const std::string &ownerID, const std::string &filePath, ByteBuffer &signature) override; void DelayUnloadTask() override; private: diff --git a/services/local_code_sign/include/local_sign_key.h b/services/local_code_sign/include/local_sign_key.h index 6c8587e..ab6d136 100644 --- a/services/local_code_sign/include/local_sign_key.h +++ b/services/local_code_sign/include/local_sign_key.h @@ -17,13 +17,12 @@ #define OHOS_LOCAL_SIGN_KEY_H #include +#include #include #include "byte_buffer.h" #include "errcode.h" -#include "hks_type.h" -#include "hks_api.h" -#include "hks_param.h" +#include "huks_param_set.h" #include "log.h" #include "sign_key.h" @@ -36,51 +35,11 @@ public: const ByteBuffer *GetSignCert() override; bool Sign(const ByteBuffer &data, ByteBuffer &ret) override; const HksCertChain *GetCertChain(); + void SetChallenge(const ByteBuffer &challenge); bool InitKey(); -private: - class HUKSParamSet { - public: - HUKSParamSet() : paramSet(nullptr) - { - } - - bool Init(const struct HksParam tmpParams[], uint32_t paramCount) - { - int32_t ret = HksInitParamSet(¶mSet); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksInitParamSet failed"); - return false; - } - ret = HksAddParams(paramSet, tmpParams, paramCount); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksAddParams failed"); - return false; - } - - ret = HksBuildParamSet(¶mSet); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksBuildParamSet failed"); - return false; - } - return true; - } - - HksParamSet *GetParamSet() const - { - return paramSet; - } - - ~HUKSParamSet() - { - if (paramSet != nullptr) { - HksFreeParamSet(¶mSet); - paramSet = nullptr; - } - } - private: - HksParamSet *paramSet = nullptr; - }; + int32_t GetFormattedCertChain(ByteBuffer &buffer); +private: LocalSignKey(); ~LocalSignKey(); @@ -97,7 +56,8 @@ private: private: ByteBuffer *cert_ = nullptr; HksCertChain *certChain_ = nullptr; - std::unique_ptr challenge_ = nullptr; + std::unique_ptr challenge_ = nullptr; + std::mutex lock_; std::string algorithm_ = "ECDSA256"; }; } diff --git a/services/local_code_sign/src/local_code_sign_service.cpp b/services/local_code_sign/src/local_code_sign_service.cpp index 09eeffa..c4d772a 100644 --- a/services/local_code_sign/src/local_code_sign_service.cpp +++ b/services/local_code_sign/src/local_code_sign_service.cpp @@ -96,22 +96,15 @@ void LocalCodeSignService::OnStop() state_ = ServiceRunningState::STATE_NOT_START; } -int32_t LocalCodeSignService::InitLocalCertificate(ByteBuffer &cert) +int32_t LocalCodeSignService::InitLocalCertificate(const ByteBuffer &challenge, ByteBuffer &certChainData) { LocalSignKey &key = LocalSignKey::GetInstance(); + key.SetChallenge(challenge); if (!key.InitKey()) { LOG_ERROR("Init key failed."); return CS_ERR_HUKS_INIT_KEY; } - const ByteBuffer *keyCert = key.GetSignCert(); - if (keyCert == nullptr) { - LOG_ERROR("Get cert failed."); - return CS_ERR_HUKS_OBTAIN_CERT; - } - if (!cert.CopyFrom(keyCert->GetBuffer(), keyCert->GetSize())) { - return CS_ERR_MEMORY; - } - return CS_SUCCESS; + return key.GetFormattedCertChain(certChainData); } int32_t LocalCodeSignService::SignLocalCode(const std::string &ownerID, const std::string &filePath, diff --git a/services/local_code_sign/src/local_code_sign_stub.cpp b/services/local_code_sign/src/local_code_sign_stub.cpp index 7b723d0..0e4bf8a 100644 --- a/services/local_code_sign/src/local_code_sign_stub.cpp +++ b/services/local_code_sign/src/local_code_sign_stub.cpp @@ -15,6 +15,7 @@ #include "local_code_sign_stub.h" +#include "cert_utils.h" #include "cs_hisysevent.h" #include "cs_hitrace.h" #include "errcode.h" @@ -61,8 +62,20 @@ int32_t LocalCodeSignStub::InitLocalCertificateInner(MessageParcel &data, Messag reply.WriteInt32(CS_ERR_NO_PERMISSION); return CS_ERR_NO_PERMISSION; } + + uint32_t challengeLen; + if (!data.ReadUint32(challengeLen) || !CheckChallengeSize(challengeLen)) { + LOG_ERROR("Get challenge size failed."); + return CS_ERR_IPC_READ_DATA; + } + ByteBuffer challenge; + const uint8_t *challengeBuffer = data.ReadBuffer(challengeLen); + if (!challenge.CopyFrom(challengeBuffer, challengeLen)) { + return CS_ERR_MEMORY; + } + ByteBuffer cert; - int32_t result = InitLocalCertificate(cert); + int32_t result = InitLocalCertificate(challenge, cert); if (!reply.WriteInt32(result)) { return CS_ERR_IPC_WRITE_DATA; } diff --git a/services/local_code_sign/src/local_sign_key.cpp b/services/local_code_sign/src/local_sign_key.cpp index c31b451..6c9ebdb 100644 --- a/services/local_code_sign/src/local_sign_key.cpp +++ b/services/local_code_sign/src/local_sign_key.cpp @@ -18,21 +18,19 @@ #include #include #include -#include +#include #include #include "byte_buffer.h" #include "cert_utils.h" #include "errcode.h" #include "log.h" -#include "securec.h" namespace OHOS { namespace Security { namespace CodeSign { static const std::string ALIAS_NAME = "LOCAL_SIGN_KEY"; static const struct HksBlob LOCAL_SIGN_KEY_ALIAS = { ALIAS_NAME.size(), (uint8_t *)ALIAS_NAME.c_str()}; -static const uint32_t CHALLENGE_LEN = 32; static const uint32_t SIGNATURE_COMMON_SIZE = 512; static const std::string SUPPORTED_SIGN_ALGORITHM = "ECDSA256"; @@ -75,6 +73,22 @@ LocalSignKey::~LocalSignKey() } } +void LocalSignKey::SetChallenge(const ByteBuffer &challenge) +{ + std::lock_guard lock(lock_); + if (challenge_) { + challenge_.reset(nullptr); + } + uint32_t len = challenge.GetSize(); + challenge_ = std::make_unique(len); + if (challenge_ == nullptr) { + return; + } + if (memcpy_s(challenge_->GetBuffer(), len, challenge.GetBuffer(), len) != EOK) { + LOG_ERROR("set challenge failed."); + } +} + bool LocalSignKey::InitKey() { int32_t ret = HksKeyExist(&LOCAL_SIGN_KEY_ALIAS, nullptr); @@ -86,6 +100,10 @@ bool LocalSignKey::InitKey() LOG_ERROR("HksKeyExist fail, ret is %{public}d!", ret); return false; } + certChain_ = QueryCertChain(); + if (certChain_ == nullptr) { + return false; + } return true; } @@ -123,6 +141,7 @@ const HksCertChain *LocalSignKey::GetCertChain() } return certChain_; } + HksCertChain *LocalSignKey::QueryCertChain() { // init attest param @@ -146,6 +165,17 @@ HksCertChain *LocalSignKey::QueryCertChain() return certChain; } +int32_t LocalSignKey::GetFormattedCertChain(ByteBuffer &buffer) +{ + if (GetCertChain() == nullptr) { + return CS_ERR_HUKS_OBTAIN_CERT; + } + if (!FormattedCertChain(certChain_, buffer)) { + return CS_ERR_MEMORY; + } + return CS_SUCCESS; +} + bool LocalSignKey::GetKeyParamSet(HUKSParamSet ¶mSet) { if (algorithm_.compare(SUPPORTED_SIGN_ALGORITHM) == 0) { @@ -156,17 +186,19 @@ bool LocalSignKey::GetKeyParamSet(HUKSParamSet ¶mSet) bool LocalSignKey::GetAttestParamSet(HUKSParamSet ¶mSet) { + std::lock_guard lock(lock_); // init challenge data by secure random function if (challenge_ == nullptr) { - challenge_ = std::make_unique(CHALLENGE_LEN); + challenge_ = GetRandomChallenge(); if (challenge_ == nullptr) { return false; } - RAND_bytes(challenge_.get(), CHALLENGE_LEN); } + + LOG_INFO("challenge in attest param."); struct HksBlob challengeBlob = { - .size = CHALLENGE_LEN, - .data = challenge_.get() + .size = challenge_->GetSize(), + .data = challenge_->GetBuffer() }; struct HksParam attestationParams[] = { { .tag = HKS_TAG_ATTESTATION_CHALLENGE, .blob = challengeBlob }, diff --git a/test/fuzztest/BUILD.gn b/test/fuzztest/BUILD.gn index 92aff8d..6c1cb4d 100644 --- a/test/fuzztest/BUILD.gn +++ b/test/fuzztest/BUILD.gn @@ -1,21 +1,24 @@ -# Copyright (c) 2023 Huawei Device Co., Ltd. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and +# Copyright (c) 2023-2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and # limitations under the License. - -import("//build/ohos.gni") - -group("fuzztest_group") { - testonly = true - if (!defined(ohos_lite)) { - deps = [ "local_code_sign_stub/signlocalcodestub_fuzzer:SignLocalCodeStubFuzzTest" ] - } -} + +import("//build/ohos.gni") + +group("fuzztest_group") { + testonly = true + if (!defined(ohos_lite)) { + deps = [ + "local_code_sign_stub/initlocalcertificate_fuzzer:InitLocalCertificateStubFuzzTest", + "local_code_sign_stub/signlocalcodestub_fuzzer:SignLocalCodeStubFuzzTest", + ] + } +} diff --git a/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/BUILD.gn b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/BUILD.gn new file mode 100644 index 0000000..3d6b295 --- /dev/null +++ b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/BUILD.gn @@ -0,0 +1,72 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/config/features.gni") +import("//build/test.gni") +import("../../../../code_signature.gni") + +ohos_fuzztest("InitLocalCertificateStubFuzzTest") { + module_out_path = "${fuzz_module_output_path}" + fuzz_config_file = "." + + sources = [ "initlocalcertificatestub_fuzzer.cpp" ] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + deps = [ "${code_signature_root_dir}/interfaces/innerkits/local_code_sign:liblocal_code_sign_sdk" ] + + include_dirs = [ + "${code_signature_root_dir}/interfaces/innerkits/local_code_sign/include", + "${code_signature_root_dir}/services/local_code_sign/include", + ] + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + ] + + sources += [ + "${code_signature_root_dir}/services/local_code_sign/src/local_code_sign_service.cpp", + "${code_signature_root_dir}/services/local_code_sign/src/local_code_sign_stub.cpp", + "${code_signature_root_dir}/services/local_code_sign/src/local_sign_key.cpp", + "${code_signature_root_dir}/services/local_code_sign/src/permission_utils.cpp", + "${code_signature_root_dir}/utils/src/cert_utils.cpp", + "${code_signature_root_dir}/utils/src/file_helper.cpp", + ] + + include_dirs += [ + "${code_signature_root_dir}/interfaces/innerkits/local_code_sign/include", + "${code_signature_root_dir}/utils/include", + ] + public_configs = [ "${code_signature_root_dir}:common_public_config" ] + configs = [ "${code_signature_root_dir}:common_utils_config" ] + deps += [ "${code_signature_root_dir}/utils:fsverity_sign_src_set" ] + external_deps += [ + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "eventhandler:libeventhandler", + "fsverity-utils:libfsverity_utils", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "huks:libhukssdk", + "init:libbegetutil", + "ipc:ipc_core", + "openssl:libcrypto_shared", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] +} diff --git a/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/corpus/init b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/corpus/init new file mode 100644 index 0000000..8bfdbf6 --- /dev/null +++ b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/corpus/init @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +123456 \ No newline at end of file diff --git a/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/initlocalcertificatestub_fuzzer.cpp b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/initlocalcertificatestub_fuzzer.cpp new file mode 100644 index 0000000..f22a9f5 --- /dev/null +++ b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/initlocalcertificatestub_fuzzer.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "initlocalcertificatestub_fuzzer.h" + +#include +#include + +#include "accesstoken_kit.h" +#include "access_token.h" +#include "local_code_sign_interface.h" +#include "local_code_sign_service.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +using namespace OHOS::Security::CodeSign; +using namespace OHOS::Security::AccessToken; + +namespace OHOS { + static uint64_t NativeTokenSet(const char *caller) + { + uint64_t tokenId = GetSelfTokenID(); + uint64_t mockTokenId = AccessTokenKit::GetNativeTokenId(caller); + SetSelfTokenID(mockTokenId); + return tokenId; + } + static void NativeTokenReset(uint64_t tokenId) + { + SetSelfTokenID(tokenId); + } + + bool InitLocalCertificateStubFuzzTest(const uint8_t *data, size_t size) + { + if ((data == nullptr) || (size == 0)) { + return false; + } + + MessageParcel datas; + datas.WriteInterfaceToken(LocalCodeSignInterface::GetDescriptor()); + if (!datas.WriteBuffer(data, size)) { + return false; + } + + uint32_t code = static_cast(LocalCodeSignInterfaceCode::INIT_LOCAL_CERTIFICATE); + MessageParcel reply; + MessageOption option; + uint64_t selfTokenId = NativeTokenSet("installs"); + DelayedSingleton::GetInstance()->OnStart(); + DelayedSingleton::GetInstance()->OnRemoteRequest(code, datas, reply, option); + NativeTokenReset(selfTokenId); + return true; + } +} + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Run your code on data */ + OHOS::InitLocalCertificateStubFuzzTest(data, size); + return 0; +} \ No newline at end of file diff --git a/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/initlocalcertificatestub_fuzzer.h b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/initlocalcertificatestub_fuzzer.h new file mode 100644 index 0000000..6647530 --- /dev/null +++ b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/initlocalcertificatestub_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEST_FUZZTEST_INITLOCALCERTIFICATESTUB_FUZZER_H +#define TEST_FUZZTEST_INITLOCALCERTIFICATESTUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "initlocalcertificatestub_fuzzer" + +#endif // TEST_FUZZTEST_INITLOCALCERTIFICATESTUB_FUZZER_H \ No newline at end of file diff --git a/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/project.xml b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/project.xml new file mode 100644 index 0000000..e7b69a5 --- /dev/null +++ b/test/fuzztest/local_code_sign_stub/initlocalcertificate_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/test/unittest/utils/src/xpm_common.cpp b/test/unittest/utils/src/xpm_common.cpp index 5b5e2dc..81934cf 100644 --- a/test/unittest/utils/src/xpm_common.cpp +++ b/test/unittest/utils/src/xpm_common.cpp @@ -21,12 +21,12 @@ #include #include #include +#include #include #include #include "code_sign_attr_utils.h" #include "log.h" -#include "securec.h" namespace OHOS { namespace Security { diff --git a/utils/include/cert_utils.h b/utils/include/cert_utils.h index eb52301..9eee534 100644 --- a/utils/include/cert_utils.h +++ b/utils/include/cert_utils.h @@ -18,13 +18,23 @@ #include +#include "byte_buffer.h" #include "hks_type.h" namespace OHOS { namespace Security { namespace CodeSign { -bool ConstructDataToCertChain(struct HksCertChain **certChain); +static const uint32_t CERT_COUNT = 4; + +bool ConstructDataToCertChain(struct HksCertChain **certChain, int certsCount = CERT_COUNT); void FreeCertChain(struct HksCertChain **certChain, const uint32_t pos); +bool FormattedCertChain(const HksCertChain *certChain, ByteBuffer &buffer); +bool GetCertChainFormBuffer(const ByteBuffer &certChainBuffer, + ByteBuffer &signCert, ByteBuffer &issuer, std::vector &chain); +int32_t VerifyAttestCertChain(const HksCertChain *certChain, const ByteBuffer &challenge); +bool GetSigningCertFromCerChain(const HksCertChain *certChain, ByteBuffer cert); +std::unique_ptr GetRandomChallenge(); +bool CheckChallengeSize(uint32_t size); } } } diff --git a/utils/include/huks_attest_verifier.h b/utils/include/huks_attest_verifier.h new file mode 100644 index 0000000..bd72531 --- /dev/null +++ b/utils/include/huks_attest_verifier.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CODE_SIGN_HUKS_ATTEST_HELPER_H +#define CODE_SIGN_HUKS_ATTEST_HELPER_H + +#include +#include "byte_buffer.h" + +namespace OHOS { +namespace Security { +namespace CodeSign { +bool GetVerifiedCert(const ByteBuffer &buffer, const ByteBuffer &challenge, ByteBuffer &cert); +} +} +} +#endif \ No newline at end of file diff --git a/utils/include/huks_param_set.h b/utils/include/huks_param_set.h new file mode 100644 index 0000000..1d4c21b --- /dev/null +++ b/utils/include/huks_param_set.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CODE_SIGN_HUKS_PARAM_SET_H +#define CODE_SIGN_HUKS_PARAM_SET_H + +#include "hks_type.h" +#include "hks_api.h" +#include "hks_param.h" +#include "log.h" + +namespace OHOS { +namespace Security { +namespace CodeSign { +class HUKSParamSet { +public: + HUKSParamSet() : paramSet(nullptr) + { + } + + ~HUKSParamSet() + { + if (paramSet != nullptr) { + HksFreeParamSet(¶mSet); + paramSet = nullptr; + } + } + + bool Init(const struct HksParam tmpParams[], uint32_t paramCount) + { + int32_t ret = HksInitParamSet(¶mSet); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksInitParamSet failed"); + return false; + } + ret = HksAddParams(paramSet, tmpParams, paramCount); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksAddParams failed"); + return false; + } + + ret = HksBuildParamSet(¶mSet); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksBuildParamSet failed"); + return false; + } + return true; + } + + HksParamSet *GetParamSet() const + { + return paramSet; + } +private: + HksParamSet *paramSet = nullptr; +}; +} +} +} +#endif \ No newline at end of file diff --git a/utils/include/openssl_utils.h b/utils/include/openssl_utils.h index c7b36d4..98054ce 100644 --- a/utils/include/openssl_utils.h +++ b/utils/include/openssl_utils.h @@ -16,11 +16,12 @@ #ifndef CODE_SIGN_OPENSSL_UTILS_H #define CODE_SIGN_OPENSSL_UTILS_H +#include #include +#include +#include #include "byte_buffer.h" -#include "openssl/x509.h" -#include "openssl/err.h" #include "log.h" namespace OHOS { @@ -37,6 +38,8 @@ void GetOpensslErrorMessage(); X509 *LoadCertFromBuffer(const uint8_t *buffer, const uint32_t size); STACK_OF(X509) *MakeStackOfCerts(const std::vector &certChain); +int CreateNIDFromOID(const std::string &oid, const std::string &shortName, + const std::string &longName); } } } diff --git a/utils/include/pkcs7_data.h b/utils/include/pkcs7_data.h index 3eda3cc..f958666 100644 --- a/utils/include/pkcs7_data.h +++ b/utils/include/pkcs7_data.h @@ -16,10 +16,11 @@ #ifndef CODE_SIGN_PKCS7_DATA_H #define CODE_SIGN_PKCS7_DATA_H +#include +#include +#include + #include "byte_buffer.h" -#include "openssl/evp.h" -#include "openssl/pkcs7.h" -#include "openssl/x509.h" namespace OHOS { namespace Security { diff --git a/utils/include/sign_key.h b/utils/include/sign_key.h index 2b48e9d..16816dc 100644 --- a/utils/include/sign_key.h +++ b/utils/include/sign_key.h @@ -19,7 +19,6 @@ #include #include "byte_buffer.h" -#include "openssl/x509.h" namespace OHOS { namespace Security { diff --git a/utils/include/signer_info.h b/utils/include/signer_info.h index 3a218f5..1a68900 100644 --- a/utils/include/signer_info.h +++ b/utils/include/signer_info.h @@ -18,20 +18,20 @@ #include #include -#include "byte_buffer.h" -#include "openssl/evp.h" -#include "openssl/pkcs7.h" -#include "openssl/x509.h" +#include +#include +#include +#include "byte_buffer.h" namespace OHOS { namespace Security { namespace CodeSign { class SignerInfo { public: - static const std::string SIGNER_OID; - static const std::string SIGNER_OID_SHORT_NAME; - static const std::string SIGNER_OID_LONG_NAME; + static const std::string OWNERID_OID; + static const std::string OWNERID_OID_SHORT_NAME; + static const std::string OWNERID_OID_LONG_NAME; static int ParseOwnerIdFromSignature(const ByteBuffer &sigbuffer, std::string &ownerID); bool InitSignerInfo(const std::string &ownerID, X509 *cert, const EVP_MD *md, const ByteBuffer &contentData, diff --git a/utils/src/cert_utils.cpp b/utils/src/cert_utils.cpp index dc985a6..5be1efd 100644 --- a/utils/src/cert_utils.cpp +++ b/utils/src/cert_utils.cpp @@ -16,17 +16,29 @@ #include "cert_utils.h" #include +#include +#include +#include #include +#include +#include "byte_buffer.h" +#include "errcode.h" +#include "huks_param_set.h" #include "log.h" namespace OHOS { namespace Security { namespace CodeSign { static const uint32_t CERT_DATA_SIZE = 8192; -static const uint32_t CERT_COUNT = 4; +static const uint32_t CHALLENGE_LEN = 32; -bool ConstructDataToCertChain(struct HksCertChain **certChain) +static inline uint8_t *CastToUint8Ptr(uint32_t *ptr) +{ + return reinterpret_cast(ptr); +} + +bool ConstructDataToCertChain(struct HksCertChain **certChain, int certsCount) { *certChain = static_cast(malloc(sizeof(struct HksCertChain))); if (*certChain == nullptr) { @@ -75,6 +87,108 @@ void FreeCertChain(struct HksCertChain **certChain, const uint32_t pos) free(*certChain); *certChain = nullptr; } + +bool FormattedCertChain(const HksCertChain *certChain, ByteBuffer &buffer) +{ + uint32_t certsCount = certChain->certsCount; + int totalLen = sizeof(uint32_t); + for (uint32_t i = 0; i < certsCount; i++) { + totalLen += sizeof(uint32_t) + certChain->certs[i].size; + } + + buffer.Resize(totalLen); + if (!buffer.PutData(0, CastToUint8Ptr(&certsCount), sizeof(uint32_t))) { + return false; + } + int pos = sizeof(uint32_t); + for (uint32_t i = 0; i < certsCount; i++) { + if (!buffer.PutData(pos, CastToUint8Ptr(&certChain->certs[i].size), sizeof(uint32_t))) { + return false; + } + pos += sizeof(uint32_t); + if (!buffer.PutData(pos, certChain->certs[i].data, certChain->certs[i].size)) { + return false; + } + pos += certChain->certs[i].size; + } + return true; +} + +static inline bool CheckSizeAndAssign(uint8_t *&bufferPtr, uint32_t &restSize, uint32_t &retSize) +{ + if (restSize < sizeof(uint32_t)) { + return false; + } + retSize = *reinterpret_cast(bufferPtr); + bufferPtr += sizeof(uint32_t); + restSize -= sizeof(uint32_t); + return true; +} + +static inline bool CheckSizeAndCopy(uint8_t *&bufferPtr, uint32_t &restSize, const uint32_t size, + ByteBuffer &ret) +{ + if (restSize < size) { + return false; + } + if (!ret.CopyFrom(bufferPtr, size)) { + return false; + } + bufferPtr += size; + restSize -= size; + return true; +} + +bool GetCertChainFormBuffer(const ByteBuffer &certChainBuffer, + ByteBuffer &signCert, ByteBuffer &issuer, std::vector &chain) +{ + uint8_t *rawPtr = certChainBuffer.GetBuffer(); + if (rawPtr == nullptr || certChainBuffer.GetSize() < sizeof(uint32_t)) { + return false; + } + uint32_t certsCount = *reinterpret_cast(rawPtr); + rawPtr += sizeof(uint32_t); + + uint32_t certSize; + bool ret = true; + uint32_t restSize = certChainBuffer.GetSize() - sizeof(uint32_t); + for (uint32_t i = 0; i < certsCount - 1; i++) { + if (!CheckSizeAndAssign(rawPtr, restSize, certSize)) { + return false; + } + if (i == 0) { + ret = CheckSizeAndCopy(rawPtr, restSize, certSize, signCert); + } else if (i == 1) { + ret = CheckSizeAndCopy(rawPtr, restSize, certSize, issuer); + } else { + ByteBuffer cert; + ret = CheckSizeAndCopy(rawPtr, restSize, certSize, cert); + chain.emplace_back(cert); + } + if (!ret) { + break; + } + } + return ret; +} + +std::unique_ptr GetRandomChallenge() +{ + std::unique_ptr challenge = std::make_unique(CHALLENGE_LEN); + if (challenge == nullptr) { + return nullptr; + } + RAND_bytes(challenge->GetBuffer(), CHALLENGE_LEN); + return challenge; +} + +bool CheckChallengeSize(uint32_t size) +{ + if (size > CHALLENGE_LEN) { + return false; + } + return true; +} } } } \ No newline at end of file diff --git a/utils/src/huks_attest_verifier.cpp b/utils/src/huks_attest_verifier.cpp new file mode 100644 index 0000000..8485dce --- /dev/null +++ b/utils/src/huks_attest_verifier.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "huks_attest_verifier.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "byte_buffer.h" +#include "cert_utils.h" +#include "log.h" +#include "openssl_utils.h" + +namespace OHOS { +namespace Security { +namespace CodeSign { +static const std::string ATTEST_ROOT_CA_PATH = "/system/etc/security/trusted_attest_root_ca.cer"; +static const std::vector ATTESTTATION_EXTENSION = { + "1.3.6.1.4.1.2011.2.376.1.3", + "AttestationInfo", + "Attestation Information" +}; + +static const std::vector SA_INFO_EXTENSION = { + "1.3.6.1.4.1.2011.2.376.2.1.3.1", + "SA INFO", + "SystemAbiliy Information" +}; + +static const std::vector CHALLENGE_EXTENSION = { + "1.3.6.1.4.1.2011.2.376.2.1.4", + "Challenge", + "Challenge" +}; + +static const std::string LOCAL_CODE_SIGN_SA_NAME = "local_code_sign"; + +static bool g_verifierInited = false; +static int g_saNid = 0; +static int g_challengeNid = 0; +static int g_attestationNid = 0; + +static inline int GetNidFromDefination(const std::vector &defVector) +{ + return CreateNIDFromOID(defVector[0], defVector[1], defVector[defVector.size() - 1]); +} + +static void InitVerifier() +{ + if (g_verifierInited) { + return; + } + g_saNid = GetNidFromDefination(SA_INFO_EXTENSION); + g_challengeNid = GetNidFromDefination(CHALLENGE_EXTENSION); + g_attestationNid = GetNidFromDefination(ATTESTTATION_EXTENSION); + LOG_DEBUG("g_saNid = %{public}d, g_challengeNid = %{public}d, g_attestationNid = %{public}d", + g_saNid, g_challengeNid, g_attestationNid); + g_verifierInited = true; +} + +static bool AddCAToStore(X509_STORE *store) +{ + FILE *fp = fopen(ATTEST_ROOT_CA_PATH.c_str(), "r"); + if (fp == nullptr) { + LOG_ERROR("Open file failed."); + return false; + } + + X509 *caCert = nullptr; + do { + caCert = PEM_read_X509(fp, nullptr, nullptr, nullptr); + if (caCert == nullptr) { + break; + } + if (X509_STORE_add_cert(store, caCert) <= 0) { + LOG_ERROR("add cert to X509 store failed"); + GetOpensslErrorMessage(); + } + LOG_INFO("Add root CA subject name = %{public}s", + X509_NAME_oneline(X509_get_subject_name(caCert), nullptr, 0)); + } while (caCert != nullptr); + (void) fclose(fp); + return true; +} + +static bool VerifyIssurCert(X509 *cert, STACK_OF(X509) *chain) +{ + X509_STORE *store = X509_STORE_new(); + if (store == nullptr) { + return false; + } + + bool ret = false; + X509_STORE_CTX *storeCtx = nullptr; + + do { + if (!AddCAToStore(store)) { + break; + } + storeCtx = X509_STORE_CTX_new(); + if (storeCtx == nullptr) { + break; + } + + if (!X509_STORE_CTX_init(storeCtx, store, cert, chain)) { + LOG_ERROR("init X509_STORE_CTX failed."); + break; + } + X509_STORE_CTX_set_purpose(storeCtx, X509_PURPOSE_ANY); + int index = X509_verify_cert(storeCtx); + if (index <= 0) { + index = X509_STORE_CTX_get_error(storeCtx); + LOG_ERROR("Verify cert failed, msg = %{public}s", X509_verify_cert_error_string(index)); + break; + } + ret = true; + } while (0); + if (!ret) { + GetOpensslErrorMessage(); + } + X509_STORE_CTX_free(storeCtx); + X509_STORE_free(store); + return ret; +} + +static bool VerifySigningCert(X509 *signCert, X509 *issuerCert) +{ + EVP_PKEY *key = X509_get0_pubkey(issuerCert); + if (key == nullptr) { + LOG_ERROR("get pub key failed."); + return false; + } + if (X509_verify(signCert, key) <= 0) { + LOG_ERROR("verify signing cert failed."); + GetOpensslErrorMessage(); + return false; + } + return true; +} + +static bool CompareTargetValue(int nid, uint8_t *data, int size, const ByteBuffer &challenge) +{ + if (nid == g_saNid) { + std::string str(reinterpret_cast(data), size); + LOG_INFO("compare with proc = %{private}s", str.c_str()); + return str.find(LOCAL_CODE_SIGN_SA_NAME) != std::string::npos; + } else if (nid == g_challengeNid) { + LOG_INFO("compare with challenge"); + return (static_cast(size) == challenge.GetSize()) + || (memcmp(data, challenge.GetBuffer(), size) == 0); + } + return true; +} + +static bool ParseASN1Sequence(uint8_t *data, int size, const ByteBuffer &challenge) +{ + STACK_OF(ASN1_TYPE) *types = d2i_ASN1_SEQUENCE_ANY( + nullptr, const_cast(&data), size); + if (types == nullptr) { + return false; + } + + int num = sk_ASN1_TYPE_num(types); + int curNid = -1; + bool ret = true; + for (int i = 0; i < num; i++) { + ASN1_TYPE *type = sk_ASN1_TYPE_value(types, i); + if (type->type == V_ASN1_SEQUENCE) { + ret = ParseASN1Sequence(type->value.sequence->data, type->value.sequence->length, + challenge); + } else if (type->type == V_ASN1_OBJECT) { + ASN1_OBJECT *obj = type->value.object; + curNid = OBJ_obj2nid(obj); + } else if (type->type == V_ASN1_OCTET_STRING) { + ASN1_OCTET_STRING *value = type->value.octet_string; + ret = CompareTargetValue(curNid, value->data, value->length, challenge); + } + if (!ret) { + break; + } + } + return true; +} + +static bool VerifyExtension(X509 *cert, const ByteBuffer &challenge) +{ + const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert); + int num; + + if ((num = sk_X509_EXTENSION_num(exts)) <= 0) { + LOG_ERROR("Get extension failed."); + return false; + } + + InitVerifier(); + for (int i = 0; i < num; i++) { + X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext); + if (obj == nullptr) { + LOG_ERROR("Get ans1 object faild"); + continue; + } + int curNid = OBJ_obj2nid(obj); + if (g_attestationNid == curNid) { + const ASN1_OCTET_STRING *extData = X509_EXTENSION_get_data(ext); + ParseASN1Sequence(extData->data, extData->length, challenge); + } + } + return true; +} + +bool GetVerifiedCert(const ByteBuffer &buffer, const ByteBuffer &challenge, ByteBuffer &certBuffer) +{ + std::vector certChainBuffer; + ByteBuffer issuerBuffer; + if (!GetCertChainFormBuffer(buffer, certBuffer, issuerBuffer, certChainBuffer)) { + LOG_ERROR("Get cert chain failed."); + return false; + } + + X509 *issuerCert = LoadCertFromBuffer(issuerBuffer.GetBuffer(), issuerBuffer.GetSize()); + if (issuerCert == nullptr) { + LOG_ERROR("Load issuerCert cert failed."); + return false; + } + + bool ret = false; + X509 *signCert = nullptr; + STACK_OF(X509 *) certChain = nullptr; + do { + certChain = MakeStackOfCerts(certChainBuffer); + if (certChain == nullptr) { + LOG_ERROR("Load cert chain failed."); + break; + } + if (!VerifyIssurCert(issuerCert, certChain)) { + LOG_ERROR("Verify issuer cert not pass."); + break; + } + LOG_DEBUG("Verify issuer cert pass"); + + signCert = LoadCertFromBuffer(certBuffer.GetBuffer(), certBuffer.GetSize()); + if (signCert == nullptr) { + LOG_ERROR("Load signing cert failed."); + break; + } + + if (!VerifySigningCert(signCert, issuerCert)) { + break; + } + LOG_DEBUG("Verify sign cert pass"); + + if (!VerifyExtension(signCert, challenge)) { + LOG_ERROR("Verify extension failed."); + break; + } + LOG_INFO("Verify success"); + ret = true; + } while (0); + X509_free(signCert); + X509_free(issuerCert); + sk_X509_pop_free(certChain, X509_free); + return ret; +} +} +} +} \ No newline at end of file diff --git a/utils/src/openssl_utils.cpp b/utils/src/openssl_utils.cpp index d1d73c2..0f41c5c 100644 --- a/utils/src/openssl_utils.cpp +++ b/utils/src/openssl_utils.cpp @@ -52,17 +52,30 @@ STACK_OF(X509) *MakeStackOfCerts(const std::vector &certChain) if (certs == nullptr) { return nullptr; } + for (const ByteBuffer &cert: certChain) { X509 *tmp = LoadCertFromBuffer(cert.GetBuffer(), cert.GetSize()); + if ((tmp == nullptr) || (!sk_X509_push(certs, tmp))) { // including each cert in certs and stack of certs sk_X509_pop_free(certs, X509_free); certs = nullptr; + ERR_LOG_WITH_OPEN_SSL_MSG("Push cert failed."); break; } } return certs; } + +int CreateNIDFromOID(const std::string &oid, const std::string &shortName, + const std::string &longName) +{ + int nid = OBJ_txt2nid(oid.c_str()); + if (nid == NID_undef) { + nid = OBJ_create(oid.c_str(), shortName.c_str(), longName.c_str()); + } + return nid; +} } } } diff --git a/utils/src/pkcs7_data.cpp b/utils/src/pkcs7_data.cpp index 292ca80..6b9fe9e 100644 --- a/utils/src/pkcs7_data.cpp +++ b/utils/src/pkcs7_data.cpp @@ -16,11 +16,12 @@ #include "pkcs7_data.h" #include +#include +#include #include "log.h" -#include "openssl/asn1.h" #include "openssl_utils.h" -#include "securec.h" + namespace OHOS { namespace Security { diff --git a/utils/src/signer_info.cpp b/utils/src/signer_info.cpp index 4205e1a..a79f704 100644 --- a/utils/src/signer_info.cpp +++ b/utils/src/signer_info.cpp @@ -17,14 +17,15 @@ #include #include -#include #include #include #include #include -#include "securec.h" +#include + #include "errcode.h" #include "log.h" +#include "openssl_utils.h" namespace OHOS { namespace Security { @@ -32,9 +33,10 @@ namespace CodeSign { static constexpr int INVALID_SIGN_ALGORITHM_NID = -1; static constexpr int MAX_SIGNATURE_SIZE = 1024; // 1024: max signature length -const std::string SignerInfo::SIGNER_OID = "1.3.6.1.4.1.2011.2.376.1.4.1"; // OID used for code signing to mark owner ID -const std::string SignerInfo::SIGNER_OID_SHORT_NAME = "ownerID"; -const std::string SignerInfo::SIGNER_OID_LONG_NAME = "Code Signature Owner ID"; +// OID used for code signing to mark owner ID +const std::string SignerInfo::OWNERID_OID = "1.3.6.1.4.1.2011.2.376.1.4.1"; +const std::string SignerInfo::OWNERID_OID_SHORT_NAME = "ownerID"; +const std::string SignerInfo::OWNERID_OID_LONG_NAME = "Code Signature Owner ID"; bool SignerInfo::InitSignerInfo(const std::string &ownerID, X509 *cert, const EVP_MD *md, const ByteBuffer &contentData, bool carrySigningTime) @@ -225,12 +227,7 @@ PKCS7_SIGNER_INFO *SignerInfo::GetSignerInfo() int SignerInfo::AddOwnerID(const std::string &ownerID) { - int nid = OBJ_txt2nid(SIGNER_OID.c_str()); - if (nid == NID_undef) { - OBJ_create(SIGNER_OID.c_str(), SIGNER_OID_SHORT_NAME.c_str(), SIGNER_OID_LONG_NAME.c_str()); - nid = OBJ_txt2nid(SIGNER_OID.c_str()); - } - + int nid = CreateNIDFromOID(OWNERID_OID, OWNERID_OID_SHORT_NAME, OWNERID_OID_LONG_NAME); ASN1_STRING *ownerIDAsn1 = ASN1_STRING_new(); ASN1_STRING_set(ownerIDAsn1, ownerID.c_str(), ownerID.length()); int ret = PKCS7_add_signed_attribute(p7info_, nid, V_ASN1_UTF8STRING, ownerIDAsn1); @@ -245,12 +242,7 @@ int SignerInfo::AddOwnerID(const std::string &ownerID) int SignerInfo::ParseOwnerIdFromSignature(const ByteBuffer &sigbuffer, std::string &ownerID) { - int nid = OBJ_txt2nid(SIGNER_OID.c_str()); - if (nid == NID_undef) { - OBJ_create(SIGNER_OID.c_str(), SIGNER_OID_SHORT_NAME.c_str(), SIGNER_OID_LONG_NAME.c_str()); - nid = OBJ_txt2nid(SIGNER_OID.c_str()); - } - + int nid = CreateNIDFromOID(OWNERID_OID, OWNERID_OID_SHORT_NAME, OWNERID_OID_LONG_NAME); BIO *bio = BIO_new_mem_buf(sigbuffer.GetBuffer(), sigbuffer.GetSize()); if (bio == nullptr) { ERR_LOG_WITH_OPEN_SSL_MSG("BIO_new_mem_buf failed"); -- Gitee