* 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.
*/
#ifndef CODE_SIGN_FSVERITY_UTILS_HELPER_H
#define CODE_SIGN_FSVERITY_UTILS_HELPER_H
#include <cerrno>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <libfsverity.h>
#include <sys/stat.h>
#include <unistd.h>
#include "errcode.h"
#include "byte_buffer.h"
#include "log.h"
#include "fdsan.h"
namespace OHOS {
namespace Security {
namespace CodeSign {
class FsverityUtilsHelper {
public:
static FsverityUtilsHelper &GetInstance();
bool GenerateFormattedDigest(const char *path, ByteBuffer &ret);
bool GenerateFormattedDigestFromFd(int32_t fd, ByteBuffer &ret);
static void ErrorMsgLogCallback(const char *msg);
private:
FsverityUtilsHelper();
~FsverityUtilsHelper();
FsverityUtilsHelper(const FsverityUtilsHelper &source) = delete;
FsverityUtilsHelper &operator = (const FsverityUtilsHelper &source) = delete;
void Init();
bool ComputeDigest(const char *path, struct libfsverity_digest **digest);
bool ComputeDigestFromFd(int32_t fd, struct libfsverity_digest **digest);
bool FormatDigest(libfsverity_digest *digest, uint8_t *buffer);
class FileReader {
public:
bool Open(const char *path)
{
if (path == nullptr) {
LOG_ERROR("Invalid parameter, path is null.");
return false;
}
if (fd_ > 0) {
LOG_ERROR("File is already opened.");
return false;
}
fd_ = open(path, O_RDONLY);
if (fd_ <= 0) {
LOG_ERROR("Open file failed, path = %{public}s, errno = <%{public}d, %{public}s>",
path, errno, strerror(errno));
return false;
}
FDSAN_MARK(fd_);
return true;
}
bool OpenFromFd(int32_t fd)
{
if (fd_ > 0) {
LOG_ERROR("File is already opened.");
return false;
}
if (fd <= 0) {
LOG_ERROR("Invalid fd=%{public}d", fd);
return false;
}
fd_ = dup(fd);
if (fd_ <= 0) {
LOG_ERROR("dup fd failed, errno = <%{public}d, %{public}s>", errno, strerror(errno));
return false;
}
FDSAN_MARK(fd_);
return true;
}
bool GetFileSize(uint64_t *size)
{
if (size == nullptr) {
LOG_ERROR("Invalid parameter, size is null.");
return false;
}
struct stat st;
if (fstat(fd_, &st) != 0) {
LOG_ERROR("Stat file failed, errno = <%{public}d, %{public}s>",
errno, strerror(errno));
return false;
}
*size = st.st_size;
return true;
}
~FileReader()
{
if (fd_ > 0) {
FDSAN_CLOSE(fd_);
fd_ = -1;
}
}
static int ReadFileCallback(void *f, void *buf, size_t count)
{
if (f == nullptr || buf == nullptr) {
return CS_ERR_FILE_READ;
}
FileReader *reader = static_cast<FileReader *>(f);
return reader->ReadBytes(static_cast<uint8_t *>(buf), count);
}
private:
int ReadBytes(uint8_t *buf, size_t count)
{
if (buf == nullptr) {
return CS_ERR_FILE_READ;
}
if (fd_ <= 0) {
return CS_ERR_FILE_READ;
}
while (count) {
ssize_t bytesRead = read(fd_, buf, count);
if (bytesRead <= 0) {
return CS_ERR_FILE_READ;
}
buf += bytesRead;
count -= static_cast<size_t>(bytesRead);
}
return CS_SUCCESS;
}
int fd_ = -1;
};
};
}
}
}
#endif