diff --git a/frameworks/cert_manager_standard/main/common/include/cm_x509.h b/frameworks/cert_manager_standard/main/common/include/cm_x509.h index 47a4cb893a96f5953d99eceb0d61191f9980b373..0d0a1f07f83b8f5d0b1447bdbb0122d2f01a979b 100644 --- a/frameworks/cert_manager_standard/main/common/include/cm_x509.h +++ b/frameworks/cert_manager_standard/main/common/include/cm_x509.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "cm_type.h" #ifdef __cplusplus extern "C" { @@ -42,6 +43,9 @@ extern "C" { #define CM_ORGANIZATION_UNIT_NAME "OU" #define ASN1_TAG_TYPE_SEQ 0x30 + +DEFINE_STACK_OF(char) + enum CmCertFormat { CM_CERT_FORMAT_PEM, CM_CERT_FORMAT_DER @@ -58,6 +62,15 @@ struct DataTime { X509 *InitCertContext(const uint8_t *certBuf, uint32_t size); +/** + * @brief Create STACKOF(X509) from a buffer + * + * @param[in] certBuf P7B file buffer. + * @param[in] size Buffer's size. + * @return STACK_OF(X509)* Stack of X509 certificate. + */ +STACK_OF(X509) *InitCertStackContext(const uint8_t *certBuf, uint32_t size); + int32_t GetX509SerialNumber(X509 *x509cert, char *outBuf, uint32_t outBufMaxSize); int32_t GetX509SubjectName(const X509 *x509cert, const char *subjectObjName, char *outBuf, uint32_t outBufMaxSize); diff --git a/frameworks/cert_manager_standard/main/common/src/cm_x509.c b/frameworks/cert_manager_standard/main/common/src/cm_x509.c index 00ba31aee522dc94678080ee965cf1a2642af1e4..ab55b390810034b33a902fb5518c7b9b6869edd8 100644 --- a/frameworks/cert_manager_standard/main/common/src/cm_x509.c +++ b/frameworks/cert_manager_standard/main/common/src/cm_x509.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,112 @@ X509 *InitCertContext(const uint8_t *certBuf, uint32_t size) return x509; } +static int32_t FindStringInStack(STACK_OF(char) *sk, const char *target) +{ + if (sk == NULL || target == NULL) { + CM_LOG_E("null pointer"); + return CMR_ERROR; + } + int num = sk_char_num(sk); + for (int i = 0; i < num; i++) { + char *str = sk_char_value(sk, i); + if (str && strcmp(str, target) == 0) { + CM_LOG_I("found fingerprint"); + return i; + } + } + return CMR_ERROR; +} + +static int32_t DumplicateCerts(STACK_OF(X509) *certStack, STACK_OF(X509) *deduplicateStack) +{ + if (certStack == NULL || deduplicateStack == NULL) { + CM_LOG_E("certStack or deduplicateStack is null"); + return CMR_ERROR_NULL_POINTER; + } + STACK_OF(char) *fingerprintStack = sk_char_new_null(); + if (fingerprintStack == NULL) { + CM_LOG_E("fingerprintStack is null"); + return CMR_ERROR_MALLOC_FAIL; + } + int32_t ret = CM_SUCCESS; + int certNum = sk_X509_num(certStack); + for (int i = 0; i < certNum; ++i) { + X509 *cert = sk_X509_value(certStack, i); + char fingerprint[FINGERPRINT_MAX_SIZE] = {0}; + int32_t fingerprintLength = GetX509Fingerprint(cert, fingerprint, sizeof(fingerprint)); + if (fingerprintLength < 0) { + continue; + } + // check is fingerprint exist or not. + int32_t fpIdx = FindStringInStack(fingerprintStack, fingerprint); + if (fpIdx != CMR_ERROR) { + continue; + } + X509 *dupCert = X509_dup(cert); + if (dupCert == NULL) { + CM_LOG_E("dupCert is null"); + ret = CMR_ERROR_NULL_POINTER; + break; + } + char *dupFingerprint = strdup(fingerprint); + if (dupFingerprint == NULL) { + X509_free(dupCert); + CM_LOG_E("dupFingerprint is null"); + ret = CMR_ERROR_NULL_POINTER; + break; + } + sk_X509_push(deduplicateStack, dupCert); + sk_char_push(fingerprintStack, dupFingerprint); + } + sk_char_pop_free(fingerprintStack, (void (*)(char *))free); + return ret; +} + +STACK_OF(X509) *InitCertStackContext(const uint8_t *certBuf, uint32_t size) +{ + if (certBuf == NULL || size > MAX_LEN_CERTIFICATE || size == 0) { + CM_LOG_E("invalid params"); + return NULL; + } + BIO *bio = BIO_new_mem_buf(certBuf, (int)size); + if (bio == NULL) { + CM_LOG_E("bio is null"); + return NULL; + } + PKCS7 *p7 = d2i_PKCS7_bio(bio, NULL); + BIO_free(bio); + if (p7 == NULL) { + CM_LOG_E("p7 is null"); + return NULL; + } + if (p7->d.sign == NULL) { + CM_LOG_E("p7->d.sign is null"); + PKCS7_free(p7); + return NULL; + } + STACK_OF(X509) *certStack = p7->d.sign->cert; + if (certStack == NULL) { + CM_LOG_E("certStack is null"); + PKCS7_free(p7); + return NULL; + } + STACK_OF(X509) *deduplicateStack = sk_X509_new_null(); + if (deduplicateStack == NULL) { + CM_LOG_E("deduplicateStack is null"); + PKCS7_free(p7); + return NULL; + } + int32_t ret = DumplicateCerts(certStack, deduplicateStack); + PKCS7_free(p7); + if (ret != CM_SUCCESS) { + CM_LOG_E("deduplicate certs failed, ret = %d", ret); + sk_X509_pop_free(deduplicateStack, X509_free); + return NULL; + } + return deduplicateStack; +} + int32_t GetX509SerialNumber(X509 *x509cert, char *outBuf, uint32_t outBufMaxSize) { if (outBuf == NULL || x509cert == NULL) { diff --git a/frameworks/cert_manager_standard/main/os_dependency/cm_ipc/include/cm_ipc_client.h b/frameworks/cert_manager_standard/main/os_dependency/cm_ipc/include/cm_ipc_client.h index 48d2d935dafef1e923ddf122e62969d9a7aa5d84..76aea96c70186d5c7adc86d64d94c3e6f8ba0ebb 100755 --- a/frameworks/cert_manager_standard/main/os_dependency/cm_ipc/include/cm_ipc_client.h +++ b/frameworks/cert_manager_standard/main/os_dependency/cm_ipc/include/cm_ipc_client.h @@ -69,8 +69,8 @@ int32_t CmClientGetUserCertInfo(const struct CmBlob *certUri, const uint32_t sto int32_t CmClientSetUserCertStatus(const struct CmBlob *certUri, const uint32_t store, const uint32_t status); -int32_t CmClientInstallUserTrustedCert(const struct CmBlob *userCert, const struct CmBlob *certAlias, - const uint32_t userId, const uint32_t status, struct CmBlob *certUri); +int32_t CmClientInstallUserTrustedCert(const struct CmInstallCertInfo *installInfo, + const enum CmCertFileFormat certFormat, const uint32_t status, struct CmBlob *certUri); int32_t CmClientUninstallUserTrustedCert(const struct CmBlob *certUri); diff --git a/frameworks/cert_manager_standard/main/os_dependency/cm_ipc/src/cm_ipc_client.c b/frameworks/cert_manager_standard/main/os_dependency/cm_ipc/src/cm_ipc_client.c index fe4fd0fc85bf44382611177a31846a6fdfc658a8..8d2fad28f9561799e6fde817fa59abddb2769ba5 100644 --- a/frameworks/cert_manager_standard/main/os_dependency/cm_ipc/src/cm_ipc_client.c +++ b/frameworks/cert_manager_standard/main/os_dependency/cm_ipc/src/cm_ipc_client.c @@ -944,9 +944,17 @@ int32_t CmClientSetUserCertStatus(const struct CmBlob *certUri, const uint32_t s return SetUserCertStatus(CM_MSG_SET_USER_CERTIFICATE_STATUS, certUri, store, status); } -int32_t CmClientInstallUserTrustedCert(const struct CmBlob *userCert, const struct CmBlob *certAlias, - const uint32_t userId, const uint32_t status, struct CmBlob *certUri) +int32_t CmClientInstallUserTrustedCert(const struct CmInstallCertInfo *installInfo, + const enum CmCertFileFormat certFormat, const uint32_t status, struct CmBlob *certUri) { + if (CmCheckInstallCertInfo(installInfo) != CM_SUCCESS) { + CM_LOG_E("check installCertInfo invalid"); + return CMR_ERROR_INVALID_ARGUMENT; + } + const struct CmBlob *userCert = installInfo->userCert; + const struct CmBlob *certAlias = installInfo->certAlias; + uint32_t userId = installInfo->userId; + if (CmCheckBlob(userCert) != CM_SUCCESS || CmCheckBlob(certAlias) != CM_SUCCESS || CmCheckBlob(certUri) != CM_SUCCESS) { CM_LOG_E("invalid input params"); @@ -961,6 +969,7 @@ int32_t CmClientInstallUserTrustedCert(const struct CmBlob *userCert, const stru { .tag = CM_TAG_PARAM1_BUFFER, .blob = *certAlias }, { .tag = CM_TAG_PARAM0_UINT32, .uint32Param = userId }, { .tag = CM_TAG_PARAM1_UINT32, .uint32Param = status }, + { .tag = CM_TAG_PARAM2_UINT32, .uint32Param = certFormat }, }; do { diff --git a/interfaces/innerkits/cert_manager_standard/main/include/cert_manager_api.h b/interfaces/innerkits/cert_manager_standard/main/include/cert_manager_api.h index c70284d413f30f47fdb50c8456dde5c2e931731e..f1b92704e350e71059e98be86c890ff1e693d096 100644 --- a/interfaces/innerkits/cert_manager_standard/main/include/cert_manager_api.h +++ b/interfaces/innerkits/cert_manager_standard/main/include/cert_manager_api.h @@ -86,6 +86,9 @@ CM_API_EXPORT int32_t CmGetUserCACertList(const struct UserCAProperty *property, CM_API_EXPORT int32_t CmGetCertStorePath(const enum CmCertType type, const uint32_t userId, char *path, uint32_t pathLen); +CM_API_EXPORT int32_t CmInstallUserTrustedP7BCert(const struct CmInstallCertInfo *installCertInfo, const bool status, + struct CertUriList *certUriList); + #ifdef __cplusplus } #endif diff --git a/interfaces/innerkits/cert_manager_standard/main/include/cm_type.h b/interfaces/innerkits/cert_manager_standard/main/include/cm_type.h index 028612dfb2f1b7155a4770d5a5ee5532a618cc8e..bdb0ce0262eab45844ca4cee4d742ef48ed654cc 100644 --- a/interfaces/innerkits/cert_manager_standard/main/include/cm_type.h +++ b/interfaces/innerkits/cert_manager_standard/main/include/cm_type.h @@ -40,6 +40,7 @@ extern "C" { #define MAX_SUFFIX_LEN 16 #define MAX_COUNT_CERTIFICATE 256 #define MAX_COUNT_CERTIFICATE_ALL 512 +#define MAX_P7B_INSTALL_COUNT 20 #define MAX_LEN_URI 256 #define MAX_AUTH_LEN_URI 256 #define MAX_LEN_CERT_ALIAS 129 /* include 1 byte: the terminator('\0') */ @@ -177,6 +178,7 @@ enum CmErrorCode { CMR_ERROR_CERT_COUNT_MISMATCH = -48, CMR_ERROR_GET_CERT_STATUS = -49, CMR_ERROR_GET_CERT_SUBJECT_ITEM = -50, + CMR_ERROR_INCLUDE_TOO_MANY_CERTS = -51, /* invalid argument */ CMR_ERROR_INVALID_ARGUMENT_BEGIN = -10000, @@ -470,11 +472,35 @@ enum CmCertScope { CM_GLOBAL_USER = 2, }; +enum CmCertFileFormat { + PEM_DER = 0, + P7B = 1, +}; + struct UserCAProperty { uint32_t userId; enum CmCertScope scope; }; +struct CmInstallCertInfo { + const struct CmBlob *userCert; + const struct CmBlob *certAlias; + uint32_t userId; +}; + +struct CertUriList { + uint32_t certCount; + struct CmBlob *uriList; +}; + +struct InstallUserCertParams { + struct CmContext *cmContext; + struct CmBlob *userCert; + struct CmBlob *certAlias; + struct CmBlob *outData; + uint32_t status; +}; + static inline bool CmIsAdditionOverflow(uint32_t a, uint32_t b) { return (UINT32_MAX - a) < b; @@ -488,6 +514,24 @@ static inline int32_t CmCheckBlob(const struct CmBlob *blob) return CM_SUCCESS; } +static inline int32_t CmCheckInstallUserCertParams(const struct InstallUserCertParams *params) +{ + if (params == NULL || params->cmContext == NULL || CmCheckBlob(params->certAlias) != CM_SUCCESS || + CmCheckBlob(params->userCert) != CM_SUCCESS || CmCheckBlob(params->outData) != CM_SUCCESS) { + return CMR_ERROR_INVALID_ARGUMENT; + } + return CM_SUCCESS; +} + +static inline int32_t CmCheckInstallCertInfo(const struct CmInstallCertInfo *installCertInfo) +{ + if (installCertInfo == NULL || CmCheckBlob(installCertInfo->certAlias) != CM_SUCCESS || + CmCheckBlob(installCertInfo->userCert) != CM_SUCCESS) { + return CMR_ERROR_INVALID_ARGUMENT; + } + return CM_SUCCESS; +} + #ifdef __cplusplus } #endif diff --git a/interfaces/innerkits/cert_manager_standard/source/cert_manager_api.c b/interfaces/innerkits/cert_manager_standard/source/cert_manager_api.c index 11a40363d81dbc927cf8303cb3ead91f14df1748..b05e3e9f875aebe892fbef9c57edfb52f913e107 100644 --- a/interfaces/innerkits/cert_manager_standard/source/cert_manager_api.c +++ b/interfaces/innerkits/cert_manager_standard/source/cert_manager_api.c @@ -373,30 +373,114 @@ CM_API_EXPORT int32_t CmInstallSystemAppCert(const struct CmAppCertParam *certPa return ret; } -CM_API_EXPORT int32_t CmInstallUserCACert(const struct CmBlob *userCert, - const struct CmBlob *certAlias, const uint32_t userId, const bool status, struct CmBlob *certUri) + +static int32_t CmInstallUserTrustedCertByFormat(const struct CmInstallCertInfo *installCertInfo, bool status, + struct CmBlob *certUri, const enum CmCertFileFormat certFormat) { - CM_LOG_I("enter install user ca cert"); - if ((userCert == NULL) || (certAlias == NULL) || (certUri == NULL)) { + CM_LOG_I("enter install user ca cert by format"); + if (CmCheckInstallCertInfo(installCertInfo) != CM_SUCCESS || CmCheckBlob(certUri) != CM_SUCCESS) { + CM_LOG_E("check installCertInfo failed"); return CMR_ERROR_INVALID_ARGUMENT; } bool isAdvSecMode = false; int32_t ret = CheckAdvSecMode(&isAdvSecMode); if (ret != CM_SUCCESS) { + CM_LOG_E("check advSecMode failed, ret = %d", ret); return ret; } if (isAdvSecMode) { - CM_LOG_E("InstallUserTrustedCert: the device enters advanced security mode"); + CM_LOG_E("the device enters advanced security mode"); return CMR_ERROR_DEVICE_ENTER_ADVSECMODE; } uint32_t uStatus = status ? 0 : 1; // 0 indicates the certificate enabled status - ret = CmClientInstallUserTrustedCert(userCert, certAlias, userId, uStatus, certUri); + ret = CmClientInstallUserTrustedCert(installCertInfo, certFormat, uStatus, certUri); CM_LOG_I("leave install user ca cert, result = %d", ret); return ret; } +CM_API_EXPORT int32_t CmInstallUserCACert(const struct CmBlob *userCert, + const struct CmBlob *certAlias, const uint32_t userId, const bool status, struct CmBlob *certUri) +{ + struct CmInstallCertInfo installInfo = { + .userCert = userCert, + .certAlias = certAlias, + .userId = userId + }; + int32_t ret = CmInstallUserTrustedCertByFormat(&installInfo, status, certUri, PEM_DER); + CM_LOG_I("leave install user ca cert, result = %d", ret); + return ret; +} + +static int32_t UnpackCertUriList(struct CertUriList *certUriList, uint8_t *inData, uint32_t dataSize) +{ + if (certUriList == NULL || inData == NULL || dataSize < sizeof(uint32_t)) { + CM_LOG_E("invalid argument"); + return CMR_ERROR_INVALID_ARGUMENT; + } + uint8_t *data = inData; + uint32_t certCount = (uint32_t)*data; + if (dataSize < (sizeof(uint32_t) + (certCount * MAX_LEN_URI))) { + CM_LOG_E("buffer size too small"); + return CMR_ERROR_BUFFER_TOO_SMALL; + } + data += sizeof(uint32_t); + certUriList->certCount = certCount; + + uint32_t uriListSize = (sizeof(struct CmBlob) + MAX_LEN_URI) * certCount; + struct CmBlob *uriList = (struct CmBlob *)CmMalloc(uriListSize); + if (uriList == NULL) { + CM_LOG_E("memory operation failed"); + return CMR_ERROR_MALLOC_FAIL; + } + (void)memset_s(uriList, uriListSize, 0, uriListSize); + certUriList->uriList = uriList; + + uint8_t *uriData = (uint8_t *)uriList + (sizeof(struct CmBlob) * certCount); + + if (memcpy_s(uriData, MAX_LEN_URI * certCount, data, MAX_LEN_URI * certCount) != EOK) { + CM_LOG_E("memory copy failed"); + return CMR_ERROR_MEM_OPERATION_COPY; + } + for (uint32_t i = 0; i < certCount; ++i) { + uriList[i].data = uriData; + uriList[i].size = MAX_LEN_URI; + uriData += MAX_LEN_URI; + } + return CM_SUCCESS; +} + +CM_API_EXPORT int32_t CmInstallUserTrustedP7BCert(const struct CmInstallCertInfo *installCertInfo, const bool status, + struct CertUriList *certUriList) +{ + if (CmCheckInstallCertInfo(installCertInfo) != CM_SUCCESS || certUriList == NULL) { + CM_LOG_E("invalid params"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + uint32_t outDataSize = sizeof(uint32_t) + (MAX_LEN_URI * MAX_P7B_INSTALL_COUNT); + uint8_t *outData = (uint8_t *)CmMalloc(outDataSize); + if (outData == NULL) { + CM_LOG_E("malloc failed"); + return CMR_ERROR_MALLOC_FAIL; + } + struct CmBlob certUriListBlob = { outDataSize, outData }; + int32_t ret = CmInstallUserTrustedCertByFormat(installCertInfo, status, &certUriListBlob, P7B); + if (ret != CM_SUCCESS) { + CM_LOG_E("install certs failed, ret = %d", ret); + CM_FREE_PTR(outData); + return ret; + } + ret = UnpackCertUriList(certUriList, outData, outDataSize); + CM_FREE_PTR(outData); + if (ret != CM_SUCCESS) { + CM_LOG_E("unpack certUriList failed, ret = %d", ret); + return ret; + } + return CM_SUCCESS; +} + CM_API_EXPORT int32_t CmGetUserCACertList(const struct UserCAProperty *property, struct CertList *certificateList) { CM_LOG_I("enter get user ca cert list"); @@ -434,5 +518,4 @@ CM_API_EXPORT int32_t CmGetCertStorePath(const enum CmCertType type, const uint3 } return CMR_ERROR_INVALID_ARGUMENT; -} - +} \ No newline at end of file diff --git a/interfaces/kits/napi/include/cm_napi_common.h b/interfaces/kits/napi/include/cm_napi_common.h index ea0b3339d834a36dcd2e31c695defcc0f94f8236..9bcdce1af08b963e87e02527a59502b2b3553aa0 100644 --- a/interfaces/kits/napi/include/cm_napi_common.h +++ b/interfaces/kits/napi/include/cm_napi_common.h @@ -164,6 +164,7 @@ enum ErrorCode { ALIAS_LENGTH_REACHED_LIMIT = 17500006, DEVICE_ENTER_ADVSECMODE = 17500007, PASSWORD_IS_ERROR = 17500008, + INCLUDE_TOO_MANY_CERTS = 17500010, }; enum CmJSKeyDigest { diff --git a/interfaces/kits/napi/src/cm_napi.cpp b/interfaces/kits/napi/src/cm_napi.cpp index 9fcc132fc82eddbd5807a1aaa585ea94696c17ca..a3471f303b1ca76cf4a1753acec442b04ae60718 100644 --- a/interfaces/kits/napi/src/cm_napi.cpp +++ b/interfaces/kits/napi/src/cm_napi.cpp @@ -52,6 +52,7 @@ namespace CMNapi { AddInt32Property(env, errorCode, "CM_ERROR_ALIAS_LENGTH_REACHED_LIMIT", ALIAS_LENGTH_REACHED_LIMIT); AddInt32Property(env, errorCode, "CM_ERROR_DEVICE_ENTER_ADVSECMODE", DEVICE_ENTER_ADVSECMODE); AddInt32Property(env, errorCode, "CM_ERROR_PASSWORD_IS_ERR", PASSWORD_IS_ERROR); + AddInt32Property(env, errorCode, "CM_ERROR_INCLUDE_TOO_MANY_CERTS", INCLUDE_TOO_MANY_CERTS); } static napi_value CreateCMErrorCode(napi_env env) @@ -122,6 +123,16 @@ namespace CMNapi { return scope; } + static napi_value CreateCertFileFormat(napi_env env) + { + napi_value format = nullptr; + NAPI_CALL(env, napi_create_object(env, &format)); + + AddInt32Property(env, format, "PEM_DER", PEM_DER); + AddInt32Property(env, format, "P7B", P7B); + return format; + } + static napi_value CreateAuthStorageLevel(napi_env env) { napi_value level = nullptr; @@ -146,6 +157,7 @@ extern "C" { DECLARE_NAPI_PROPERTY("CmKeyPadding", CreateCMKeyPadding(env)), DECLARE_NAPI_PROPERTY("CertType", CreateCertType(env)), DECLARE_NAPI_PROPERTY("CertScope", CreateCertScope(env)), + DECLARE_NAPI_PROPERTY("CertFileFormat", CreateCertFileFormat(env)), DECLARE_NAPI_PROPERTY("AuthStorageLevel", CreateAuthStorageLevel(env)), /* system ca */ diff --git a/interfaces/kits/napi/src/cm_napi_common.cpp b/interfaces/kits/napi/src/cm_napi_common.cpp index 3c708e5f7b3e30f2035b0f6f94d08f37b6261f27..984b32c3d9aa7209181f61bb2f2b7c82ff3577bb 100644 --- a/interfaces/kits/napi/src/cm_napi_common.cpp +++ b/interfaces/kits/napi/src/cm_napi_common.cpp @@ -36,6 +36,7 @@ static const std::string NO_AUTHORIZATION_MSG = "the application is not authoriz static const std::string ALIAS_LENGTH_REACHED_LIMIT_MSG = "the input alias length reaches the max"; static const std::string DEVICE_ENTER_ADVSECMODE_MSG = "the device enters advanced security mode"; static const std::string PASSWORD_IS_ERROR_MSG = "the input password is error"; +static const std::string INCLUDE_TOO_MANY_CERTS_MSG = "the file includes too many certs"; static const std::unordered_map NATIVE_CODE_TO_JS_CODE_MAP = { // invalid params @@ -54,6 +55,7 @@ static const std::unordered_map NATIVE_CODE_TO_JS_CODE_MAP = { { CMR_ERROR_ALIAS_LENGTH_REACHED_LIMIT, ALIAS_LENGTH_REACHED_LIMIT }, { CMR_ERROR_DEVICE_ENTER_ADVSECMODE, DEVICE_ENTER_ADVSECMODE }, { CMR_ERROR_PASSWORD_IS_ERR, PASSWORD_IS_ERROR }, + { CMR_ERROR_INCLUDE_TOO_MANY_CERTS, INCLUDE_TOO_MANY_CERTS }, }; static const std::unordered_map NATIVE_CODE_TO_MSG_MAP = { @@ -69,6 +71,7 @@ static const std::unordered_map NATIVE_CODE_TO_MSG_MAP = { { CMR_ERROR_ALIAS_LENGTH_REACHED_LIMIT, ALIAS_LENGTH_REACHED_LIMIT_MSG }, { CMR_ERROR_DEVICE_ENTER_ADVSECMODE, DEVICE_ENTER_ADVSECMODE_MSG }, { CMR_ERROR_PASSWORD_IS_ERR, PASSWORD_IS_ERROR_MSG }, + { CMR_ERROR_INCLUDE_TOO_MANY_CERTS, INCLUDE_TOO_MANY_CERTS_MSG }, }; } // namespace diff --git a/interfaces/kits/napi/src/cm_napi_user_trusted_cert.cpp b/interfaces/kits/napi/src/cm_napi_user_trusted_cert.cpp index 2ef6fd15875d09c4b3dc74db4c0597a585087dc2..a4955e6bc66a69389d86482b53e98594a235b889 100644 --- a/interfaces/kits/napi/src/cm_napi_user_trusted_cert.cpp +++ b/interfaces/kits/napi/src/cm_napi_user_trusted_cert.cpp @@ -44,6 +44,9 @@ struct UserCertAsyncContextT { struct CmBlob *userCert = nullptr; struct CmBlob *certAlias = nullptr; struct CmBlob *certUri = nullptr; + struct CertUriList *certUriList = nullptr; + CmCertFileFormat certFormat = PEM_DER; + CmCertScope certScope = CM_ALL_USER; }; using UserCertAsyncContext = UserCertAsyncContextT *; @@ -66,6 +69,10 @@ static void FreeUserCertAsyncContext(napi_env env, UserCertAsyncContext &context FreeCmBlob(context->userCert); FreeCmBlob(context->certAlias); FreeCmBlob(context->certUri); + if (context->certUriList != nullptr) { + CM_FREE_PTR(context->certUriList->uriList); + CM_FREE_PTR(context->certUriList); + } CM_FREE_PTR(context); } @@ -100,6 +107,57 @@ static int32_t GetCertAliasData(napi_env env, napi_value object, UserCertAsyncCo return CM_SUCCESS; } +static napi_value ParseCertFormat(napi_env env, napi_value object, UserCertAsyncContext context) +{ + napi_value certFormatValue = nullptr; + napi_status status = napi_get_named_property(env, object, "certFormat", &certFormatValue); + if (status != napi_ok || certFormatValue == nullptr) { + return GetInt32(env, 0); + } + uint32_t certFormat = PEM_DER; + if (ParseUint32(env, certFormatValue, certFormat) == nullptr) { + CM_LOG_E("parse uint32 failed"); + return nullptr; + } + // check support certFormat + switch (certFormat) { + case PEM_DER: + case P7B: + break; + default: + CM_LOG_E("invalid cert format: %u", certFormat); + return nullptr; + } + context->certFormat = static_cast(certFormat); + return GetInt32(env, 0); +} + +static napi_value ParseCertScope(napi_env env, napi_value object, UserCertAsyncContext context) +{ + napi_value certScopeValue = nullptr; + napi_status status = napi_get_named_property(env, object, "certScope", &certScopeValue); + if (status != napi_ok || certScopeValue == nullptr) { + return GetInt32(env, 0); + } + uint32_t certScope = PEM_DER; + if (ParseUint32(env, certScopeValue, certScope) == nullptr) { + CM_LOG_E("parse uint32 failed"); + return nullptr; + } + // check support certScope + switch (certScope) { + case CM_ALL_USER: + case CM_GLOBAL_USER: + case CM_CURRENT_USER: + break; + default: + CM_LOG_E("invalid cert scope: %u", certScope); + return nullptr; + } + context->certScope = static_cast(certScope); + return GetInt32(env, 0); +} + static napi_value ParseCertInfo(napi_env env, napi_value object, UserCertAsyncContext context) { napi_valuetype type = napi_undefined; @@ -123,13 +181,27 @@ static napi_value ParseCertInfo(napi_env env, napi_value object, UserCertAsyncCo return nullptr; } + // parse certFormat + if (ParseCertFormat(env, object, context) == nullptr) { + CM_LOG_E("parse cert file format failed"); + return nullptr; + } + + // parse certScope + if (ParseCertScope(env, object, context) == nullptr) { + CM_LOG_E("parse cert scope failed"); + return nullptr; + } + int32_t ret = GetUserCertData(env, userCertValue, &context->userCert); if (ret != CM_SUCCESS) { + CM_LOG_E("get user certData failed, ret = %d", ret); return nullptr; } ret = GetCertAliasData(env, certAliasValue, context); if (ret != CM_SUCCESS) { + CM_LOG_E("get cert aliasData failed, ret = %d", ret); return nullptr; } @@ -280,14 +352,13 @@ static napi_value ParseUninstallAllUserCertParams(napi_env env, napi_callback_in return GetInt32(env, 0); } -static void InstallUserCertExecute(napi_env env, void *data) +static int32_t InitCertUri(UserCertAsyncContext context) { - UserCertAsyncContext context = static_cast(data); context->certUri = static_cast(CmMalloc(sizeof(CmBlob))); if (context->certUri == nullptr) { CM_LOG_E("malloc certUri failed"); context->errCode = CMR_ERROR_MALLOC_FAIL; - return; + return CMR_ERROR_MALLOC_FAIL; } (void)memset_s(context->certUri, sizeof(CmBlob), 0, sizeof(CmBlob)); @@ -295,12 +366,70 @@ static void InstallUserCertExecute(napi_env env, void *data) if (context->certUri->data == nullptr) { CM_LOG_E("malloc certUri.data failed"); context->errCode = CMR_ERROR_MALLOC_FAIL; - return; + return CMR_ERROR_MALLOC_FAIL; } (void)memset_s(context->certUri->data, OUT_AUTH_URI_SIZE, 0, OUT_AUTH_URI_SIZE); context->certUri->size = OUT_AUTH_URI_SIZE; + return CM_SUCCESS; +} - context->errCode = CmInstallUserTrustedCert(context->userCert, context->certAlias, context->certUri); +static int32_t InitCertUriList(UserCertAsyncContext context) +{ + CertUriList *certUriList = static_cast(CmMalloc(sizeof(CertUriList))); + if (certUriList == nullptr) { + CM_LOG_E("malloc certUriList failed"); + context->errCode = CMR_ERROR_MALLOC_FAIL; + return CMR_ERROR_MALLOC_FAIL; + } + (void)memset_s(certUriList, sizeof(CertUriList), 0, sizeof(CertUriList)); + certUriList->certCount = 0; + context->certUriList = certUriList; + return CM_SUCCESS; +} + +static void InstallUserCertExecute(napi_env env, void *data) +{ + UserCertAsyncContext context = static_cast(data); + if (context == nullptr) { + CM_LOG_E("context is null"); + return; + } + int32_t ret = CM_SUCCESS; + uint32_t userId = 0; + if (context->certScope == CM_CURRENT_USER) { + userId = INIT_INVALID_VALUE; + } else if (context->certScope == CM_GLOBAL_USER) { + userId = 0; + } else { + CM_LOG_E("invalid certificate scope"); + context->errCode = CMR_ERROR_INVALID_ARGUMENT; + return; + } + + if (context->certFormat == P7B) { + ret = InitCertUriList(context); + if (ret != CM_SUCCESS) { + CM_LOG_E("init cert uriList failed, ret = %d", ret); + context->errCode = ret; + return; + } + CmInstallCertInfo installCertInfo = { + .userCert = context->userCert, + .certAlias = context->certAlias, + .userId = userId + }; + context->errCode = CmInstallUserTrustedP7BCert(&installCertInfo, true, context->certUriList); + return; + } + + ret = InitCertUri(context); + if (ret != CM_SUCCESS) { + CM_LOG_E("init certUri failed"); + context->errCode = ret; + return; + } + context->errCode = CmInstallUserCACert(context->userCert, context->certAlias, userId, true, context->certUri); + return; } static napi_value ConvertResultCertUri(napi_env env, const CmBlob *certUri) @@ -316,13 +445,44 @@ static napi_value ConvertResultCertUri(napi_env env, const CmBlob *certUri) return result; } +static napi_value ConvertResultCertUriList(napi_env env, const CertUriList *certUriList) +{ + if (certUriList == nullptr) { + CM_LOG_E("null pointer"); + return nullptr; + } + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + napi_value uriArray = nullptr; + NAPI_CALL(env, napi_create_array(env, &uriArray)); + + for (uint32_t i = 0; i < certUriList->certCount; ++i) { + napi_value certUri = nullptr; + NAPI_CALL(env, napi_create_string_latin1(env, reinterpret_cast(certUriList->uriList[i].data), + NAPI_AUTO_LENGTH, &certUri)); + NAPI_CALL(env, napi_set_element(env, uriArray, i, certUri)); + } + + NAPI_CALL(env, napi_set_named_property(env, result, "uriList", uriArray)); + return result; +} + +static napi_value ConvertInstallCertResult(napi_env env, const UserCertAsyncContext context) +{ + if (context->certFormat == P7B) { + return ConvertResultCertUriList(env, context->certUriList); + } + return ConvertResultCertUri(env, context->certUri); +} + static void InstallUserCertComplete(napi_env env, napi_status status, void *data) { UserCertAsyncContext context = static_cast(data); napi_value result[RESULT_NUMBER] = { nullptr }; if (context->errCode == CM_SUCCESS) { napi_create_uint32(env, 0, &result[0]); - result[1] = ConvertResultCertUri(env, context->certUri); + result[1] = ConvertInstallCertResult(env, context); } else { result[0] = GenerateBusinessError(env, context->errCode); napi_get_undefined(env, &result[1]); diff --git a/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager.h b/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager.h index 60fca892cb18ad3c8f844c10c386efaf441d91b2..4cdb1781c0df1df6066cebd1541b8910fb4456ea 100644 --- a/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager.h +++ b/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager.h @@ -93,6 +93,8 @@ int32_t RdbInsertCertProperty(const struct CertPropertyOri *propertyOri); int32_t GetObjNameFromCertData(const struct CmBlob *certData, const struct CmBlob *certAlias, struct CmBlob *objectName); +int32_t GetCertOrCredCount(const struct CmContext *context, const uint32_t store, uint32_t *certCount); + #ifdef __cplusplus } #endif diff --git a/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager_check.h b/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager_check.h index 8ffe6482c5d0227e01c398b3ef8c5581b4667663..21baf6d239f7094579e04c0c76770e334ef76e6b 100755 --- a/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager_check.h +++ b/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager_check.h @@ -50,6 +50,8 @@ int32_t CmServiceGetUserCertInfoCheck(struct CmContext *cmContext, const struct const uint32_t type, bool isCheckUid); int32_t CmServiceSetUserCertStatusCheck(struct CmContext *cmContext, const struct CmBlob *certUri); + +int32_t CheckInstallMultiCertCount(const struct CmContext *context, const uint32_t certNum); #ifdef __cplusplus } #endif diff --git a/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager_service.h b/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager_service.h index 8a505acebdaa67cbaf5f5d4fdd07ffac6b49b31d..c9e4808500d0aff853258525906903060b351645 100755 --- a/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager_service.h +++ b/services/cert_manager_standard/cert_manager_engine/main/core/include/cert_manager_service.h @@ -62,6 +62,9 @@ int32_t CmX509ToPEM(const X509 *x509, struct CmBlob *userCertPem); int32_t CmInstallUserCert(const struct CmContext *context, const struct CmBlob *userCert, const struct CmBlob *certAlias, const uint32_t status, struct CmBlob *certUri); +int32_t CmInstallMultiUserCert(const struct CmContext *context, const struct CmBlob *userCert, + const struct CmBlob *certAlias, const uint32_t status, struct CmBlob *certUri); + int32_t CmUninstallUserCert(const struct CmContext *context, const struct CmBlob *certUri); int32_t CmUninstallAllUserCert(const struct CmContext *context); diff --git a/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager.c b/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager.c index 2340b3b0d4cb2d6aa3ceda1b2c5446eece065ef3..01c1fc709ab5cbc74d857cd5ae6271e2cfa12216 100644 --- a/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager.c +++ b/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager.c @@ -559,8 +559,12 @@ int32_t CmServiceGetCallingAppCertList(const struct CmContext *context, uint32_t return CM_SUCCESS; } -static int32_t GetCertOrCredCount(const struct CmContext *context, const uint32_t store, uint32_t *certCount) +int32_t GetCertOrCredCount(const struct CmContext *context, const uint32_t store, uint32_t *certCount) { + if (context == NULL || certCount == NULL) { + CM_LOG_E("null pointer"); + return CMR_ERROR_NULL_POINTER; + } uint32_t fileCount = 0; struct CmBlob fileNames[MAX_COUNT_CERTIFICATE]; uint32_t len = MAX_COUNT_CERTIFICATE * sizeof(struct CmBlob); diff --git a/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager_check.c b/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager_check.c index e3ad6276cf49bd101f363a0b5fa3621e596bc387..546b443febae89d5207b2ca1b5e24f9a5069906d 100644 --- a/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager_check.c +++ b/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager_check.c @@ -576,3 +576,18 @@ int32_t CmServiceSetUserCertStatusCheck(struct CmContext *cmContext, const struc } return CM_SUCCESS; } + +int32_t CheckInstallMultiCertCount(const struct CmContext *context, const uint32_t certNum) +{ + uint32_t certCount = 0; + int32_t ret = GetCertOrCredCount(context, CM_USER_TRUSTED_STORE, &certCount); + if (ret != CM_SUCCESS) { + CM_LOG_E("Failed obtain cert count for store muti user cert."); + return ret; + } + if (certCount + certNum > MAX_COUNT_CERTIFICATE) { + CM_LOG_E("cert count beyond maxcount, can't install user certs"); + return CMR_ERROR_MAX_CERT_COUNT_REACHED; + } + return CM_SUCCESS; +} diff --git a/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager_service.c b/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager_service.c index 217bbc64f9877f375089abefd4991cd42202d63e..9b65f72e6efcddc5183b6cbd36d8b30d894a01bb 100644 --- a/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager_service.c +++ b/services/cert_manager_standard/cert_manager_engine/main/core/src/cert_manager_service.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "securec.h" @@ -827,6 +828,67 @@ int32_t CmInstallUserCert(const struct CmContext *context, const struct CmBlob * return ret; } +int32_t CmInstallMultiUserCert(const struct CmContext *context, const struct CmBlob *userCert, + const struct CmBlob *certAlias, const uint32_t status, struct CmBlob *certUri) +{ + if (context == NULL || userCert == NULL || certAlias == NULL || certUri->data == NULL || + certUri->size < sizeof(uint32_t)) { + CM_LOG_E("invalid argument"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + uint8_t *outData = certUri->data; + uint32_t uriListSize = 0; + + STACK_OF(X509) *certStack = InitCertStackContext(userCert->data, userCert->size); + if (certStack == NULL) { + CM_LOG_E("init certStack failed"); + return CMR_ERROR_INVALID_CERT_FORMAT; + } + uriListSize = (int32_t)sk_X509_num(certStack); + // check buffer size + uint32_t capacity = (certUri->size - sizeof(uint32_t)) / MAX_LEN_URI; + if (uriListSize > capacity) { + CM_LOG_E("check certFile include too many certs"); + sk_X509_pop_free(certStack, X509_free); + return CMR_ERROR_INCLUDE_TOO_MANY_CERTS; + } + int32_t ret = CheckInstallMultiCertCount(context, (uint32_t)uriListSize); + if (ret != CM_SUCCESS) { + CM_LOG_E("check install certs too many, ret = %d", ret); + sk_X509_pop_free(certStack, X509_free); + return ret; + } + + // set uriListSize + *((uint32_t *)outData) = uriListSize; + outData += sizeof(uint32_t); + + for (int32_t i = 0; i < uriListSize; ++i) { + struct CmBlob certPemData = { 0, NULL }; + X509 *cert = sk_X509_value(certStack, i); + ret = CmX509ToPEM(cert, &certPemData); + if (ret != CM_SUCCESS) { + CM_LOG_E("CmX509ToPem failed, ret = %d", ret); + break; + } + + // install an user cert + struct CmBlob outUri = { MAX_LEN_URI, outData }; + ret = CmInstallUserCert(context, &certPemData, certAlias, status, &outUri); + if (ret != CM_SUCCESS) { + CM_FREE_BLOB(certPemData); + CM_LOG_E("CmInstallUserCert failed, ret = %d", ret); + break; + } + CM_FREE_BLOB(certPemData); + outData += MAX_LEN_URI; + } + + sk_X509_pop_free(certStack, X509_free); + return ret; +} + static int32_t CmComparisonCallerIdWithUri(const struct CmContext *context, const struct CmBlob *certUri) { diff --git a/services/cert_manager_standard/cert_manager_service/main/os_dependency/idl/cm_ipc/cm_ipc_service.c b/services/cert_manager_standard/cert_manager_service/main/os_dependency/idl/cm_ipc/cm_ipc_service.c index 4996b7878f0459f773f106fd24d0f634ff4e8d91..a416b2cd05abd9dae97ea4f70be7442b90978c51 100644 --- a/services/cert_manager_standard/cert_manager_service/main/os_dependency/idl/cm_ipc/cm_ipc_service.c +++ b/services/cert_manager_standard/cert_manager_service/main/os_dependency/idl/cm_ipc/cm_ipc_service.c @@ -1191,6 +1191,29 @@ void CmIpcServiceSetUserCertStatus(const struct CmBlob *paramSetBlob, struct CmB CM_LOG_I("leave: ret = %d", ret); } +static int32_t CmInstallUserCertExecute(const struct InstallUserCertParams *installCertParams, + const enum CmCertFileFormat certFormat) +{ + if (CmCheckInstallUserCertParams(installCertParams) != CM_SUCCESS) { + CM_LOG_E("invalid params"); + return CMR_ERROR_NULL_POINTER; + } + int32_t ret = CM_SUCCESS; + if (certFormat == PEM_DER) { + ret = CmInstallUserCert(installCertParams->cmContext, installCertParams->userCert, + installCertParams->certAlias, installCertParams->status, installCertParams->outData); + } else if (certFormat == P7B) { + ret = CmInstallMultiUserCert(installCertParams->cmContext, installCertParams->userCert, + installCertParams->certAlias, installCertParams->status, installCertParams->outData); + } else { + ret = CMR_ERROR_NOT_SUPPORTED; + } + if (ret != CM_SUCCESS) { + CM_LOG_E("install user cert failed, certFormat = %u, ret = %d", certFormat, ret); + } + return ret; +} + void CmIpcServiceInstallUserCert(const struct CmBlob *paramSetBlob, struct CmBlob *outData, const struct CmContext *context) { @@ -1199,6 +1222,7 @@ void CmIpcServiceInstallUserCert(const struct CmBlob *paramSetBlob, struct CmBlo struct CmBlob certAlias = { 0, NULL }; uint32_t userId = 0; uint32_t status = CERT_STATUS_ENANLED; + uint32_t certFormat = PEM_DER; struct CmContext cmContext = {0}; struct CmContext oriContext = {0}; struct CmParamSet *paramSet = NULL; @@ -1207,6 +1231,7 @@ void CmIpcServiceInstallUserCert(const struct CmBlob *paramSetBlob, struct CmBlo { .tag = CM_TAG_PARAM1_BUFFER, .blob = &certAlias }, { .tag = CM_TAG_PARAM0_UINT32, .uint32Param = &userId }, { .tag = CM_TAG_PARAM1_UINT32, .uint32Param = &status }, + { .tag = CM_TAG_PARAM2_UINT32, .uint32Param = &certFormat }, }; do { @@ -1224,7 +1249,8 @@ void CmIpcServiceInstallUserCert(const struct CmBlob *paramSetBlob, struct CmBlo break; } - ret = CmInstallUserCert(&cmContext, &userCert, &certAlias, status, outData); + struct InstallUserCertParams installUserCertParams = { &cmContext, &userCert, &certAlias, outData, status }; + ret = CmInstallUserCertExecute(&installUserCertParams, certFormat); if (ret != CM_SUCCESS) { CM_LOG_E("CertManagerInstallUserCert fail, ret = %d", ret); break;