blob: 9a68eeb133900a7937ec2a85a3e2cd20e96254dc [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <blkctl/blkctl.h>
#include <blkctl/command.h>
#include <crypto/secret.h>
#include <zircon/types.h>
#include "zxcrypt.h"
namespace blkctl {
namespace zxcrypt {
using ::zxcrypt::Volume;
constexpr zx::duration kTimeout = zx::sec(3);
zx_status_t ZxcryptCommand::ReadKey(key_slot_t slot, crypto::Secret* out) {
zx_status_t rc;
BlkCtl* cmdline = this->cmdline();
// TODO(security): Add a 'max key len' to Volume when ZX-1130 is resolved.
size_t key_len = ::zxcrypt::kZx1130KeyLen;
char prompt[32];
snprintf(prompt, sizeof(prompt), "key for slot %" PRIu64, slot);
size_t hex_len = (key_len * 2) + 1;
char hex[hex_len];
uint8_t *buf;
if ((rc = out->Allocate(key_len, &buf)) != ZX_OK ||
(rc = cmdline->Prompt(prompt, hex, hex_len)) != ZX_OK ||
(rc = ParseHex(hex, buf, key_len)) != ZX_OK) {
return rc;
}
// TODO(security): ZX-1130
uint8_t zx1130[::zxcrypt::kZx1130KeyLen] = {0};
if (out->len() != sizeof(zx1130) || memcmp(out->get(), zx1130, out->len()) != 0) {
return ZX_ERR_INVALID_ARGS;
}
return ZX_OK;
}
zx_status_t Create::Run() {
zx_status_t rc;
BlkCtl* cmdline = this->cmdline();
const char* dev;
int fd;
crypto::Secret key;
if ((rc = cmdline->GetStrArg("device", &dev)) != ZX_OK || (rc = cmdline->ArgsDone()) != ZX_OK ||
(rc = OpenReadable(dev, &fd)) != ZX_OK || (rc = ReadKey(0, &key)) != ZX_OK ||
(rc = cmdline->Confirm()) != ZX_OK || (rc = ReopenWritable(&fd)) != ZX_OK) {
return rc;
}
fbl::unique_fd ufd(fd);
if ((rc = Volume::Create(fbl::move(ufd), key)) != ZX_OK) {
return rc;
}
return ZX_OK;
}
zx_status_t Open::Run() {
zx_status_t rc;
BlkCtl* cmdline = this->cmdline();
const char* dev;
key_slot_t slot;
crypto::Secret key;
int fd;
fbl::unique_ptr<Volume> volume;
fbl::unique_fd opened;
// Unlock the volume before opening it to verify the key is correct.
if ((rc = cmdline->GetStrArg("device", &dev)) != ZX_OK ||
(rc = cmdline->GetNumArg("slot", &slot)) != ZX_OK || (rc = cmdline->ArgsDone()) != ZX_OK ||
(rc = OpenReadable(dev, &fd)) != ZX_OK || (rc = ReadKey(slot, &key)) != ZX_OK) {
return rc;
}
fbl::unique_fd ufd(fd);
if ((rc = Volume::Unlock(fbl::move(ufd), key, slot, &volume)) != ZX_OK ||
(rc = volume->Open(kTimeout, &opened)) != ZX_OK) {
return rc;
}
return ZX_OK;
}
zx_status_t Enroll::Run() {
zx_status_t rc;
BlkCtl* cmdline = this->cmdline();
const char* dev;
key_slot_t slot, new_slot;
int fd;
crypto::Secret key, new_key;
fbl::unique_ptr<Volume> volume;
if ((rc = cmdline->GetStrArg("device", &dev)) != ZX_OK ||
(rc = cmdline->GetNumArg("slot", &slot)) != ZX_OK ||
(rc = cmdline->GetNumArg("new_slot", &new_slot)) != ZX_OK ||
(rc = cmdline->ArgsDone()) != ZX_OK || (rc = OpenReadable(dev, &fd)) != ZX_OK ||
(rc = ReadKey(slot, &key)) != ZX_OK || (rc = ReadKey(new_slot, &new_key)) != ZX_OK ||
(rc = cmdline->Confirm()) != ZX_OK || (rc = ReopenWritable(&fd)) != ZX_OK) {
return rc;
}
fbl::unique_fd ufd(fd);
if ((rc = Volume::Unlock(fbl::move(ufd), key, slot, &volume)) != ZX_OK ||
(rc = volume->Enroll(new_key, new_slot)) != ZX_OK) {
return rc;
}
return ZX_OK;
}
zx_status_t Revoke::Run() {
zx_status_t rc;
BlkCtl* cmdline = this->cmdline();
const char* dev;
key_slot_t slot, old_slot;
int fd;
crypto::Secret key;
fbl::unique_ptr<Volume> volume;
if ((rc = cmdline->GetStrArg("device", &dev)) != ZX_OK ||
(rc = cmdline->GetNumArg("slot", &slot)) != ZX_OK ||
(rc = cmdline->GetNumArg("old_slot", &old_slot)) != ZX_OK ||
(rc = cmdline->ArgsDone()) != ZX_OK || (rc = OpenReadable(dev, &fd)) != ZX_OK ||
(rc = ReadKey(slot, &key)) != ZX_OK || (rc = cmdline->Confirm()) != ZX_OK ||
(rc = ReopenWritable(&fd)) != ZX_OK) {
return rc;
}
fbl::unique_fd ufd(fd);
if ((rc = Volume::Unlock(fbl::move(ufd), key, slot, &volume)) != ZX_OK ||
(rc = volume->Revoke(old_slot)) != ZX_OK) {
return rc;
}
return ZX_OK;
}
zx_status_t Shred::Run() {
zx_status_t rc;
BlkCtl* cmdline = this->cmdline();
const char* dev;
key_slot_t slot;
int fd;
crypto::Secret key;
fbl::unique_ptr<Volume> volume;
// TODO(security); ZX-1138. This should also unbind the device.
if ((rc = cmdline->GetStrArg("device", &dev)) != ZX_OK ||
(rc = cmdline->GetNumArg("slot", &slot)) != ZX_OK || (rc = cmdline->ArgsDone()) != ZX_OK ||
(rc = OpenReadable(dev, &fd)) != ZX_OK || (rc = ReadKey(slot, &key)) != ZX_OK ||
(rc = cmdline->Confirm()) != ZX_OK || (rc = ReopenWritable(&fd)) != ZX_OK) {
return rc;
}
fbl::unique_fd ufd(fd);
if ((rc = Volume::Unlock(fbl::move(ufd), key, slot, &volume)) != ZX_OK ||
(rc = volume->Shred()) != ZX_OK) {
return rc;
}
return ZX_OK;
}
} // namespace zxcrypt
} // namespace blkctl