* 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
* limitations under the License.
*/
#include "key_utils.h"
#include <asm/unistd.h>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <openssl/x509.h>
#include <openssl/objects.h>
#include "log_rust.h"
#include "errcode.h"
#define ENTERPRISE_RESIGN_OID "1.3.6.1.4.1.2011.2.376.1.9"
#define ENTERPRISE_RESIGN_SN "EnterpriseAppResignCertID"
#define ENTERPRISE_RESIGN_LN "Enterprise App Resign Cert ID"
#define BINARY_CERT_OID "1.3.6.1.4.1.2011.2.376.1.8"
constexpr int KEYCTL_RESTRICT_KEYRING = 29;
using namespace OHOS::Security::CodeSign;
KeySerial AddKey(
const char *type,
const char *description,
const unsigned char *payload,
size_t pLen,
KeySerial ringId)
{
KeySerial ret = syscall(__NR_add_key,
type, description, static_cast<const void *>(payload),
pLen, ringId);
if (ret < 0) {
LOG_ERROR(LABEL, "Add certificate failed, errno = <%{public}d, %{public}s>",
errno, strerror(errno));
}
return ret;
}
KeySerial KeyctlRestrictKeyring(
KeySerial ringId,
const char *type,
const char *restriction)
{
KeySerial ret = syscall(__NR_keyctl,
KEYCTL_RESTRICT_KEYRING, ringId,
type, restriction);
if (ret < 0) {
LOG_ERROR(LABEL, "Restrict keyring failed, errno = <%{public}d, %{public}s>",
errno, strerror(errno));
}
return ret;
}
int32_t CheckCertHasEnterpriseResignExtension(const uint8_t *certDer, uint32_t certSize)
{
if (certDer == nullptr || certSize == 0) {
LOG_ERROR(LABEL, "Invalid certificate DER input");
return CS_ERR_PARAM_INVALID;
}
const unsigned char *certPtr = certDer;
X509 *cert = d2i_X509(nullptr, &certPtr, certSize);
if (cert == nullptr) {
LOG_ERROR(LABEL, "Failed to parse certificate from DER");
return CS_ERR_PARAM_INVALID;
}
const char *enterpriseResignOid = ENTERPRISE_RESIGN_OID;
int nid = OBJ_txt2nid(enterpriseResignOid);
if (nid == NID_undef) {
nid = OBJ_create(ENTERPRISE_RESIGN_OID, ENTERPRISE_RESIGN_SN, ENTERPRISE_RESIGN_LN);
}
if (nid == NID_undef) {
LOG_ERROR(LABEL, "Failed to create NID for enterprise resign OID");
X509_free(cert);
return CS_ERR_PARAM_INVALID;
}
int loc = X509_get_ext_by_NID(cert, nid, -1);
X509_free(cert);
if (loc >= 0) {
LOG_INFO(LABEL, "Found enterprise resign extension in certificate");
return CS_SUCCESS;
} else {
LOG_ERROR(LABEL, "Enterprise resign extension not found in certificate");
return CS_ERR_PARAM_INVALID;
}
}
int32_t CheckCertHasBinaryCertExtension(const uint8_t *certDer, uint32_t certSize)
{
if (certDer == nullptr || certSize == 0) {
LOG_ERROR(LABEL, "Invalid certificate DER input");
return CS_ERR_PARAM_INVALID;
}
const unsigned char *certPtr = certDer;
X509 *cert = d2i_X509(nullptr, &certPtr, certSize);
if (cert == nullptr) {
LOG_ERROR(LABEL, "Failed to parse certificate from DER");
return CS_ERR_PARAM_INVALID;
}
int extCount = X509_get_ext_count(cert);
for (int i = 0; i < extCount; i++) {
X509_EXTENSION *ext = X509_get_ext(cert, i);
if (ext == nullptr) {
continue;
}
ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
if (obj == nullptr) {
continue;
}
char oidBuf[128] = {0};
if (OBJ_obj2txt(oidBuf, sizeof(oidBuf), obj, 1) > 0 && strcmp(oidBuf, BINARY_CERT_OID) == 0) {
X509_free(cert);
LOG_INFO(LABEL, "Found binary cert extension in certificate");
return CS_SUCCESS;
}
}
X509_free(cert);
LOG_ERROR(LABEL, "Binary cert extension not found in certificate");
return CS_ERR_PARAM_INVALID;
}