1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <arpa/inet.h> 6#include <errno.h> 7#include <fcntl.h> 8#include <inttypes.h> 9#include <stddef.h> 10#include <stdint.h> 11#include <string.h> 12#include <unistd.h> 13 14#include <crypto/bytes.h> 15#include <crypto/cipher.h> 16#include <crypto/hkdf.h> 17#include <crypto/secret.h> 18#include <ddk/device.h> 19#include <ddk/driver.h> 20#include <ddk/protocol/block.h> 21#include <fbl/algorithm.h> 22#include <fbl/auto_call.h> 23#include <fbl/macros.h> 24#include <fbl/string_buffer.h> 25#include <fbl/unique_fd.h> 26#include <fbl/unique_ptr.h> 27#include <fs-management/mount.h> 28#include <fs-management/ramdisk.h> 29#include <lib/fdio/debug.h> 30#include <lib/zx/vmo.h> 31#include <lib/sync/completion.h> 32#include <zircon/compiler.h> 33#include <zircon/device/block.h> 34#include <zircon/errors.h> 35#include <zircon/status.h> 36#include <zircon/types.h> 37#include <zxcrypt/volume.h> 38 39#define ZXDEBUG 0 40 41namespace zxcrypt { 42 43// Several copies of the metadata for a zxcrypt volume is saved at the beginning and end of the 44// devices. The number of copies is given by |kMetadataBlocks * kReservedSlices|, and the locations 45// of each block can be iterated through using |Begin| and |Next|. The metadata block, or 46// superblock, consists of a fixed type GUID, an instance GUID, a 32-bit version, a set of "key 47// slots" The key slots are data cipher key material encrypted with a wrapping crypto::AEAD key 48// derived from the caller-provided root key and specific slot. 49 50// Determines what algorithms are in use when creating new zxcrypt devices. 51const Volume::Version Volume::kDefaultVersion = Volume::kAES256_XTS_SHA256; 52 53// The amount of data that can "in-flight" to the underlying block device before the zxcrypt 54// driver begins queuing transactions 55// 56// TODO(aarongreen): See ZX-1616. Tune this value. Possibly break into several smaller VMOs if we 57// want to allow some to be recycled; support for this doesn't currently exist. Up to 64 MB may be 58// in flight at once. The device's max_transfer_size will be capped at 1/4 of this value. 59const uint32_t Volume::kBufferSize = 1U << 24; 60static_assert(Volume::kBufferSize % PAGE_SIZE == 0, "kBufferSize must be page aligned"); 61 62namespace { 63 64// The zxcrypt driver 65const char* kDriverLib = "/boot/driver/zxcrypt.so"; 66 67// The number of metadata blocks in a reserved metadata slice, each holding a copy of the 68// superblock. 69const size_t kMetadataBlocks = 2; 70 71// HKDF labels 72const size_t kMaxLabelLen = 16; 73const char* kWrapKeyLabel = "wrap key %" PRIu64; 74const char* kWrapIvLabel = "wrap iv %" PRIu64; 75 76// Header is type GUID | instance GUID | version. 77const size_t kHeaderLen = sizeof(zxcrypt_magic) + GUID_LEN + sizeof(uint32_t); 78 79void SyncComplete(block_op_t* block, zx_status_t status) { 80 // Use the 32bit command field to shuttle the response back to the callsite that's waiting on 81 // the completion 82 block->command = status; 83 sync_completion_signal(static_cast<sync_completion_t*>(block->cookie)); 84} 85 86// Performs synchronous I/O 87zx_status_t SyncIO(zx_device_t* dev, uint32_t cmd, void* buf, size_t off, size_t len) { 88 zx_status_t rc; 89 90 if (!dev || !buf || len == 0) { 91 xprintf("bad parameter(s): dev=%p, buf=%p, len=%zu\n", dev, buf, len); 92 return ZX_ERR_INVALID_ARGS; 93 } 94 95 block_protocol_t proto; 96 if ((rc = device_get_protocol(dev, ZX_PROTOCOL_BLOCK, &proto)) != ZX_OK) { 97 xprintf("block protocol not support\n"); 98 return ZX_ERR_NOT_SUPPORTED; 99 } 100 101 zx::vmo vmo; 102 if ((rc = zx::vmo::create(len, 0, &vmo)) != ZX_OK) { 103 xprintf("zx::vmo::create failed: %s\n", zx_status_get_string(rc)); 104 return rc; 105 } 106 107 block_info_t info; 108 size_t op_size; 109 proto.ops->query(proto.ctx, &info, &op_size); 110 111 size_t bsz = info.block_size; 112 ZX_DEBUG_ASSERT(off / bsz <= UINT32_MAX); 113 ZX_DEBUG_ASSERT(len / bsz <= UINT32_MAX); 114 115 char raw[op_size]; 116 block_op_t* block = reinterpret_cast<block_op_t*>(raw); 117 118 sync_completion_t completion; 119 sync_completion_reset(&completion); 120 121 block->command = cmd; 122 block->rw.vmo = vmo.get(); 123 block->rw.length = static_cast<uint32_t>(len / bsz); 124 block->rw.offset_dev = static_cast<uint32_t>(off / bsz); 125 block->rw.offset_vmo = 0; 126 block->rw.pages = nullptr; 127 block->completion_cb = SyncComplete; 128 block->cookie = &completion; 129 130 if (cmd == BLOCK_OP_WRITE && (rc = vmo.write(buf, 0, len)) != ZX_OK) { 131 xprintf("zx::vmo::write failed: %s\n", zx_status_get_string(rc)); 132 return rc; 133 } 134 135 proto.ops->queue(proto.ctx, block); 136 sync_completion_wait(&completion, ZX_TIME_INFINITE); 137 138 rc = block->command; 139 if (rc != ZX_OK) { 140 xprintf("Block I/O failed: %s\n", zx_status_get_string(rc)); 141 return rc; 142 } 143 144 if (cmd == BLOCK_OP_READ && (rc = vmo.read(buf, 0, len)) != ZX_OK) { 145 xprintf("zx::vmo::read failed: %s\n", zx_status_get_string(rc)); 146 return rc; 147 } 148 149 return ZX_OK; 150} 151 152} // namespace 153 154Volume::~Volume() {} 155 156// Library methods 157 158zx_status_t Volume::Create(fbl::unique_fd fd, const crypto::Secret& key, 159 fbl::unique_ptr<Volume>* out) { 160 zx_status_t rc; 161 162 if (!fd) { 163 xprintf("bad parameter(s): fd=%d\n", fd.get()); 164 return ZX_ERR_INVALID_ARGS; 165 } 166 167 fbl::AllocChecker ac; 168 fbl::unique_ptr<Volume> volume(new (&ac) Volume(fbl::move(fd))); 169 if (!ac.check()) { 170 xprintf("allocation failed: %zu bytes\n", sizeof(Volume)); 171 return ZX_ERR_NO_MEMORY; 172 } 173 174 if ((rc = volume->Init()) != ZX_OK || (rc = volume->CreateBlock()) != ZX_OK || 175 (rc = volume->SealBlock(key, 0)) != ZX_OK || (rc = volume->CommitBlock()) != ZX_OK) { 176 return rc; 177 } 178 179 if (out) { 180 *out = fbl::move(volume); 181 } 182 return ZX_OK; 183} 184 185zx_status_t Volume::Unlock(fbl::unique_fd fd, const crypto::Secret& key, key_slot_t slot, 186 fbl::unique_ptr<Volume>* out) { 187 zx_status_t rc; 188 189 if (!fd || !out) { 190 xprintf("bad parameter(s): fd=%d, out=%p\n", fd.get(), out); 191 return ZX_ERR_INVALID_ARGS; 192 } 193 194 fbl::AllocChecker ac; 195 fbl::unique_ptr<Volume> volume(new (&ac) Volume(fbl::move(fd))); 196 if (!ac.check()) { 197 xprintf("allocation failed: %zu bytes\n", sizeof(Volume)); 198 return ZX_ERR_NO_MEMORY; 199 } 200 if ((rc = volume->Init()) != ZX_OK || (rc = volume->Unseal(key, slot)) != ZX_OK) { 201 return rc; 202 } 203 204 *out = fbl::move(volume); 205 return ZX_OK; 206} 207 208zx_status_t Volume::Open(const zx::duration& timeout, fbl::unique_fd* out) { 209 zx_status_t rc; 210 ssize_t res; 211 212 // Get the full device path 213 fbl::StringBuffer<PATH_MAX> path; 214 path.Resize(path.capacity()); 215 if ((res = ioctl_device_get_topo_path(fd_.get(), path.data(), path.capacity())) < 0) { 216 rc = static_cast<zx_status_t>(res); 217 xprintf("could not find parent device: %s\n", zx_status_get_string(rc)); 218 return rc; 219 } 220 path.Resize(strlen(path.c_str())); 221 path.Append("/zxcrypt/block"); 222 223 // Early return if already bound 224 fbl::unique_fd fd(open(path.c_str(), O_RDWR)); 225 if (fd) { 226 out->reset(fd.release()); 227 return ZX_OK; 228 } 229 230 // Bind the device 231 if ((res = ioctl_device_bind(fd_.get(), kDriverLib, strlen(kDriverLib))) < 0) { 232 rc = static_cast<zx_status_t>(res); 233 xprintf("could not bind zxcrypt driver: %s\n", zx_status_get_string(rc)); 234 return rc; 235 } 236 if ((rc = wait_for_device(path.c_str(), timeout.get())) != ZX_OK) { 237 xprintf("zxcrypt driver failed to bind: %s\n", zx_status_get_string(rc)); 238 return rc; 239 } 240 fd.reset(open(path.c_str(), O_RDWR)); 241 if (!fd) { 242 xprintf("failed to open zxcrypt volume\n"); 243 return ZX_ERR_NOT_FOUND; 244 } 245 246 out->reset(fd.release()); 247 return ZX_OK; 248} 249 250zx_status_t Volume::Enroll(const crypto::Secret& key, key_slot_t slot) { 251 zx_status_t rc; 252 ZX_DEBUG_ASSERT(!dev_); // Cannot enroll from driver 253 254 if (!block_.get()) { 255 xprintf("not initialized\n"); 256 return ZX_ERR_BAD_STATE; 257 } 258 if (slot >= num_key_slots_) { 259 xprintf("bad parameter(s): slot=%" PRIu64 "\n", slot); 260 return ZX_ERR_INVALID_ARGS; 261 } 262 if ((rc = SealBlock(key, slot)) != ZX_OK || (rc = CommitBlock()) != ZX_OK) { 263 return rc; 264 } 265 266 return ZX_OK; 267} 268 269zx_status_t Volume::Revoke(key_slot_t slot) { 270 zx_status_t rc; 271 ZX_DEBUG_ASSERT(!dev_); // Cannot revoke from driver 272 273 if (!block_.get()) { 274 xprintf("not initialized\n"); 275 return ZX_ERR_BAD_STATE; 276 } 277 if (slot >= num_key_slots_) { 278 xprintf("bad parameter(s): slot=%" PRIu64 "\n", slot); 279 return ZX_ERR_INVALID_ARGS; 280 } 281 zx_off_t off = kHeaderLen + (slot_len_ * slot); 282 crypto::Bytes invalid; 283 if ((rc = invalid.Randomize(slot_len_)) != ZX_OK || (rc = block_.Copy(invalid, off)) != ZX_OK || 284 (rc = CommitBlock()) != ZX_OK) { 285 return rc; 286 } 287 288 return ZX_OK; 289} 290 291zx_status_t Volume::Shred() { 292 zx_status_t rc; 293 ZX_DEBUG_ASSERT(!dev_); // Cannot shred from driver 294 295 if (!block_.get()) { 296 xprintf("not initialized\n"); 297 return ZX_ERR_BAD_STATE; 298 } 299 if ((rc = block_.Randomize()) != ZX_OK) { 300 return rc; 301 } 302 for (rc = Begin(); rc == ZX_ERR_NEXT; rc = Next()) { 303 if ((rc = Write()) != ZX_OK) { 304 return rc; 305 } 306 } 307 Reset(); 308 309 return ZX_OK; 310} 311 312// Driver methods 313 314zx_status_t Volume::Unlock(zx_device_t* dev, const crypto::Secret& key, key_slot_t slot, 315 fbl::unique_ptr<Volume>* out) { 316 zx_status_t rc; 317 318 if (!dev || !out) { 319 xprintf("bad parameter(s): dev=%p, out=%p\n", dev, out); 320 return ZX_ERR_INVALID_ARGS; 321 } 322 fbl::AllocChecker ac; 323 fbl::unique_ptr<Volume> volume(new (&ac) Volume(dev)); 324 if (!ac.check()) { 325 xprintf("allocation failed: %zu bytes\n", sizeof(Volume)); 326 return ZX_ERR_NO_MEMORY; 327 } 328 if ((rc = volume->Init()) != ZX_OK || (rc = volume->Unseal(key, slot)) != ZX_OK) { 329 return rc; 330 } 331 332 *out = fbl::move(volume); 333 return ZX_OK; 334} 335 336zx_status_t Volume::Bind(crypto::Cipher::Direction direction, crypto::Cipher* cipher) const { 337 zx_status_t rc; 338 ZX_DEBUG_ASSERT(dev_); // Cannot bind from library 339 340 if (!cipher) { 341 xprintf("bad parameter(s): cipher=%p\n", cipher); 342 return ZX_ERR_INVALID_ARGS; 343 } 344 if (!block_.get()) { 345 xprintf("not initialized\n"); 346 return ZX_ERR_BAD_STATE; 347 } 348 if ((rc = cipher->Init(cipher_, direction, data_key_, data_iv_, block_.len())) != ZX_OK) { 349 return rc; 350 } 351 352 return ZX_OK; 353} 354 355// Private methods 356 357Volume::Volume(fbl::unique_fd&& fd) : dev_(nullptr), fd_(fbl::move(fd)) { 358 Reset(); 359} 360 361Volume::Volume(zx_device_t* dev) : dev_(dev), fd_() { 362 Reset(); 363} 364 365// Configuration methods 366 367zx_status_t Volume::Init() { 368 zx_status_t rc; 369 Reset(); 370 auto cleanup = fbl::MakeAutoCall([&] { Reset(); }); 371 372 // Get block info; align our blocks to pages 373 block_info_t blk; 374 if ((rc = Ioctl(IOCTL_BLOCK_GET_INFO, nullptr, 0, &blk, sizeof(blk))) < 0) { 375 xprintf("failed to get block info: %s\n", zx_status_get_string(rc)); 376 return rc; 377 } 378 // Check that we meet the minimum size. 379 if (blk.block_count < kMetadataBlocks) { 380 xprintf("device is too small; have %" PRIu64 " blocks, need %" PRIu64 "\n", blk.block_count, 381 kMetadataBlocks); 382 return ZX_ERR_NOT_SUPPORTED; 383 } 384 reserved_blocks_ = kMetadataBlocks; 385 // Allocate block buffer 386 if ((rc = block_.Resize(blk.block_size)) != ZX_OK) { 387 return rc; 388 } 389 // Get FVM info 390 fvm_info_t fvm; 391 switch ((rc = Ioctl(IOCTL_BLOCK_FVM_QUERY, nullptr, 0, &fvm, sizeof(fvm)))) { 392 case ZX_OK: { 393 // This *IS* an FVM partition. 394 // Ensure first kReservedSlices + 1 slices are allocated 395 size_t blocks_per_slice = fvm.slice_size / blk.block_size; 396 reserved_blocks_ = fbl::round_up(reserved_blocks_, blocks_per_slice); 397 reserved_slices_ = reserved_blocks_ / blocks_per_slice; 398 size_t required = reserved_slices_ + 1; 399 size_t range = 1; 400 query_request_t request; 401 query_response_t response; 402 extend_request_t extend; 403 for (size_t i = 0; i < required; i += range) { 404 // Ask about the next contiguous range 405 request.count = 1; 406 request.vslice_start[0] = i + 1; 407 if ((rc = Ioctl(IOCTL_BLOCK_FVM_VSLICE_QUERY, &request, sizeof(request), &response, 408 sizeof(response))) < 0 || 409 response.count == 0 || (range = response.vslice_range[0].count) == 0) { 410 xprintf("ioctl_block_fvm_vslice_query failed: %s\n", zx_status_get_string(rc)); 411 return rc; 412 } 413 // If already allocated, continue 414 if (response.vslice_range[0].allocated) { 415 continue; 416 }; 417 // Otherwise, allocate it 418 extend.offset = i + 1; 419 extend.length = fbl::min(required - i, range); 420 if ((rc = Ioctl(IOCTL_BLOCK_FVM_EXTEND, &extend, sizeof(extend), nullptr, 0)) < 0) { 421 xprintf("failed to extend FVM partition: %s\n", zx_status_get_string(rc)); 422 return rc; 423 } 424 } 425 break; 426 } 427 case ZX_ERR_NOT_SUPPORTED: 428 // This is *NOT* an FVM partition. 429 break; 430 default: 431 // An error occurred 432 return rc; 433 } 434 435 cleanup.cancel(); 436 return ZX_OK; 437} 438 439zx_status_t Volume::Configure(Volume::Version version) { 440 zx_status_t rc; 441 442 switch (version) { 443 case Volume::kAES256_XTS_SHA256: 444 aead_ = crypto::AEAD::kAES128_GCM_SIV; 445 cipher_ = crypto::Cipher::kAES256_XTS; 446 digest_ = crypto::digest::kSHA256; 447 break; 448 449 default: 450 xprintf("unknown version: %u\n", version); 451 return ZX_ERR_NOT_SUPPORTED; 452 } 453 454 size_t key_len, iv_len, tag_len; 455 if ((rc = crypto::Cipher::GetKeyLen(cipher_, &key_len)) != ZX_OK || 456 (rc = crypto::Cipher::GetIVLen(cipher_, &iv_len)) != ZX_OK || 457 (rc = crypto::AEAD::GetTagLen(aead_, &tag_len)) != ZX_OK || 458 (rc = crypto::digest::GetDigestLen(digest_, &digest_len_)) != ZX_OK) { 459 return rc; 460 } 461 462 slot_len_ = key_len + iv_len + tag_len; 463 num_key_slots_ = (block_.len() - kHeaderLen) / slot_len_; 464 if (num_key_slots_ == 0) { 465 xprintf("block size is too small; have %zu, need %zu\n", block_.len(), 466 kHeaderLen + slot_len_); 467 return ZX_ERR_NOT_SUPPORTED; 468 } 469 470 return ZX_OK; 471} 472 473zx_status_t Volume::DeriveSlotKeys(const crypto::Secret& key, key_slot_t slot) { 474 zx_status_t rc; 475 476 crypto::HKDF hkdf; 477 char label[kMaxLabelLen]; 478 if ((rc = hkdf.Init(digest_, key, guid_)) != ZX_OK) { 479 return rc; 480 } 481 snprintf(label, kMaxLabelLen, kWrapKeyLabel, slot); 482 size_t len; 483 if ((rc = crypto::AEAD::GetKeyLen(aead_, &len)) != ZX_OK || 484 (rc = hkdf.Derive(label, len, &wrap_key_)) != ZX_OK) { 485 xprintf("failed to derive wrap key: %s\n", zx_status_get_string(rc)); 486 return rc; 487 } 488 snprintf(label, kMaxLabelLen, kWrapIvLabel, slot); 489 crypto::Secret wrap_iv; 490 if ((rc = crypto::AEAD::GetIVLen(aead_, &len)) != ZX_OK || 491 (rc = hkdf.Derive(label, len, &wrap_iv_)) != ZX_OK) { 492 xprintf("failed to derive wrap IV: %s\n", zx_status_get_string(rc)); 493 return rc; 494 } 495 496 return ZX_OK; 497} 498 499void Volume::Reset() { 500 block_.Resize(0); 501 offset_ = UINT64_MAX; 502 aead_ = crypto::AEAD::kUninitialized; 503 wrap_key_.Clear(); 504 cipher_ = crypto::Cipher::kUninitialized; 505 data_key_.Clear(); 506 slot_len_ = 0; 507 num_key_slots_ = 0; 508 digest_ = crypto::digest::kUninitialized; 509} 510 511// Block methods 512 513zx_status_t Volume::Begin() { 514 offset_ = 0; 515 return ZX_ERR_NEXT; 516} 517 518zx_status_t Volume::Next() { 519 offset_ += block_.len(); 520 return (offset_ / block_.len()) < kMetadataBlocks ? ZX_ERR_NEXT : ZX_ERR_STOP; 521} 522 523zx_status_t Volume::CreateBlock() { 524 zx_status_t rc; 525 526 // Create a "backdrop" of random data 527 if ((rc = block_.Randomize()) != ZX_OK) { 528 return rc; 529 } 530 531 // Write the variant 1/version 1 type GUID according to RFC 4122. 532 // TODO(aarongreen): ZX-2106. This and other magic numbers should be moved to a public/zircon 533 // header, and the dependency removed. 534 uint8_t* out = block_.get(); 535 memcpy(out, zxcrypt_magic, sizeof(zxcrypt_magic)); 536 out += sizeof(zxcrypt_magic); 537 538 // Create a variant 1/version 4 instance GUID according to RFC 4122. 539 if ((rc = guid_.Randomize(GUID_LEN)) != ZX_OK) { 540 return rc; 541 } 542 guid_[6] = (guid_[6] & 0x0F) | 0x40; 543 guid_[8] = (guid_[8] & 0x3F) | 0x80; 544 memcpy(out, guid_.get(), GUID_LEN); 545 out += GUID_LEN; 546 547 // Write the 32-bit version. 548 if ((rc = Configure(kDefaultVersion)) != ZX_OK) { 549 return rc; 550 } 551 uint32_t version = htonl(kDefaultVersion); 552 memcpy(out, &version, sizeof(version)); 553 554 // Generate the data key and IV, and save the AAD. 555 size_t key_len, iv_len; 556 if ((rc = crypto::Cipher::GetKeyLen(cipher_, &key_len)) != ZX_OK || 557 (rc = crypto::Cipher::GetIVLen(cipher_, &iv_len)) != ZX_OK || 558 (rc = data_key_.Generate(key_len)) != ZX_OK || (rc = data_iv_.Resize(iv_len)) != ZX_OK || 559 (rc = data_iv_.Randomize()) != ZX_OK || 560 (rc = header_.Copy(block_.get(), kHeaderLen)) != ZX_OK) { 561 return rc; 562 } 563 564 return ZX_OK; 565} 566 567zx_status_t Volume::CommitBlock() { 568 zx_status_t rc; 569 570 // Make a copy to compare the read result to; this reduces the number of 571 // writes we must do. 572 crypto::Bytes block; 573 if ((rc = block.Copy(block_)) != ZX_OK) { 574 return rc; 575 } 576 for (rc = Begin(); rc == ZX_ERR_NEXT; rc = Next()) { 577 // Only write back blocks that don't match 578 if (Read() == ZX_OK && block_ == block) { 579 continue; 580 } 581 if ((rc = block_.Copy(block)) != ZX_OK || (rc = Write()) != ZX_OK) { 582 xprintf("write failed for offset %" PRIu64 ": %s\n", offset_, zx_status_get_string(rc)); 583 } 584 } 585 return ZX_OK; 586} 587 588zx_status_t Volume::SealBlock(const crypto::Secret& key, key_slot_t slot) { 589 zx_status_t rc; 590 591 if (slot >= num_key_slots_) { 592 xprintf("bad key slot: %" PRIu64 "\n", slot); 593 return ZX_ERR_OUT_OF_RANGE; 594 } 595 596 // Encrypt the data key 597 zx_off_t nonce; 598 crypto::AEAD aead; 599 crypto::Bytes ptext, ctext; 600 zx_off_t off = kHeaderLen + (slot_len_ * slot); 601 zx_off_t data_key_off = 0; 602 zx_off_t data_iv_off = data_key_.len(); 603 if ((rc = ptext.Copy(data_key_.get(), data_key_.len(), data_key_off)) != ZX_OK || 604 (rc = ptext.Copy(data_iv_.get(), data_iv_.len(), data_iv_off)) != ZX_OK || 605 (rc = DeriveSlotKeys(key, slot)) != ZX_OK || 606 (rc = aead.InitSeal(aead_, wrap_key_, wrap_iv_)) != ZX_OK || 607 (rc = aead.Seal(ptext, header_, &nonce, &ctext)) != ZX_OK) { 608 return rc; 609 } 610 // Check that we'll be able to unseal. 611 if (memcmp(&nonce, wrap_iv_.get(), sizeof(nonce)) != 0) { 612 xprintf("unexpected nonce: %" PRIu64 "\n", nonce); 613 return ZX_ERR_INTERNAL; 614 } 615 616 memcpy(block_.get() + off, ctext.get(), ctext.len()); 617 return ZX_OK; 618} 619 620zx_status_t Volume::Unseal(const crypto::Secret& key, key_slot_t slot) { 621 zx_status_t rc; 622 623 for (rc = Begin(); rc == ZX_ERR_NEXT; rc = Next()) { 624 if ((rc = Read()) != ZX_OK) { 625 xprintf("failed to read block at %" PRIu64 ": %s\n", offset_, zx_status_get_string(rc)); 626 } else if ((rc = UnsealBlock(key, slot)) != ZX_OK) { 627 xprintf("failed to open block at %" PRIu64 ": %s\n", offset_, zx_status_get_string(rc)); 628 } else { 629 return CommitBlock(); 630 } 631 } 632 633 return ZX_ERR_ACCESS_DENIED; 634} 635 636zx_status_t Volume::UnsealBlock(const crypto::Secret& key, key_slot_t slot) { 637 zx_status_t rc; 638 639 // Check the type GUID matches |kTypeGuid|. 640 uint8_t* in = block_.get(); 641 if (memcmp(in, zxcrypt_magic, sizeof(zxcrypt_magic)) != 0) { 642 xprintf("not a zxcrypt device\n"); 643 return ZX_ERR_NOT_SUPPORTED; 644 } 645 in += sizeof(zxcrypt_magic); 646 647 // Save the instance GUID 648 if ((rc = guid_.Copy(in, GUID_LEN)) != ZX_OK) { 649 return rc; 650 } 651 in += GUID_LEN; 652 653 // Read the version 654 uint32_t version; 655 memcpy(&version, in, sizeof(version)); 656 in += sizeof(version); 657 if ((rc != Configure(Version(ntohl(version)))) != ZX_OK) { 658 return rc; 659 } 660 if (slot >= num_key_slots_) { 661 xprintf("bad key slot: %" PRIu64 "\n", slot); 662 return ZX_ERR_OUT_OF_RANGE; 663 } 664 if ((rc != DeriveSlotKeys(key, slot)) != ZX_OK) { 665 return rc; 666 } 667 668 // Extract nonce from IV. 669 zx_off_t nonce; 670 memcpy(&nonce, wrap_iv_.get(), sizeof(nonce)); 671 672 // Read in the data 673 crypto::AEAD aead; 674 crypto::Bytes ptext, ctext, data_key; 675 zx_off_t off = kHeaderLen + (slot_len_ * slot); 676 677 size_t key_off, key_len, iv_off, iv_len; 678 uint8_t* key_buf; 679 if ((rc = crypto::Cipher::GetKeyLen(cipher_, &key_len)) != ZX_OK || 680 (rc = crypto::Cipher::GetIVLen(cipher_, &iv_len)) != ZX_OK || 681 (rc = data_key_.Allocate(key_len, &key_buf)) != ZX_OK) { 682 return rc; 683 } 684 685 key_off = 0; 686 iv_off = data_key_.len(); 687 if ((rc = ctext.Copy(block_.get() + off, slot_len_)) != ZX_OK || 688 (rc = aead.InitOpen(aead_, wrap_key_, wrap_iv_)) != ZX_OK || 689 (rc = header_.Copy(block_.get(), kHeaderLen)) != ZX_OK || 690 (rc = aead.Open(nonce, ctext, header_, &ptext)) != ZX_OK || 691 (rc = data_iv_.Copy(ptext.get() + iv_off, iv_len)) != ZX_OK) { 692 return rc; 693 } 694 memcpy(key_buf, ptext.get() + key_off, key_len); 695 696 return ZX_OK; 697} 698 699// Device methods 700 701zx_status_t Volume::Ioctl(int op, const void* in, size_t in_len, void* out, size_t out_len) { 702 zx_status_t rc; 703 // Don't include debug messages here; some errors (e.g. ZX_ERR_NOT_SUPPORTED) 704 // are expected under certain conditions (e.g. calling FVM ioctls on a non-FVM 705 // device). Handle error reporting at the call sites instead. 706 if (dev_) { 707 size_t actual; 708 if ((rc = device_ioctl(dev_, op, in, in_len, out, out_len, &actual)) < 0) { 709 return rc; 710 } 711 } else { 712 ssize_t res; 713 if ((res = fdio_ioctl(fd_.get(), op, in, in_len, out, out_len)) < 0) { 714 return static_cast<zx_status_t>(res); 715 } 716 } 717 return ZX_OK; 718} 719 720zx_status_t Volume::Read() { 721 zx_status_t rc; 722 723 if (dev_) { 724 if ((rc = SyncIO(dev_, BLOCK_OP_READ, block_.get(), offset_, block_.len())) != ZX_OK) { 725 return rc; 726 } 727 } else { 728 if (lseek(fd_.get(), offset_, SEEK_SET) < 0) { 729 xprintf("lseek(%d, %" PRIu64 ", SEEK_SET) failed: %s\n", fd_.get(), offset_, 730 strerror(errno)); 731 return ZX_ERR_IO; 732 } 733 ssize_t res; 734 if ((res = read(fd_.get(), block_.get(), block_.len())) < 0) { 735 xprintf("read(%d, %p, %zu) failed: %s\n", fd_.get(), block_.get(), block_.len(), 736 strerror(errno)); 737 return ZX_ERR_IO; 738 } 739 if (static_cast<size_t>(res) != block_.len()) { 740 xprintf("short read: have %zd, need %zu\n", res, block_.len()); 741 return ZX_ERR_IO; 742 } 743 } 744 745 return ZX_OK; 746} 747 748zx_status_t Volume::Write() { 749 zx_status_t rc; 750 751 if (dev_) { 752 if ((rc = SyncIO(dev_, BLOCK_OP_WRITE, block_.get(), offset_, block_.len())) != ZX_OK) { 753 return rc; 754 } 755 } else { 756 if (lseek(fd_.get(), offset_, SEEK_SET) < 0) { 757 xprintf("lseek(%d, %" PRIu64 ", SEEK_SET) failed: %s\n", fd_.get(), offset_, 758 strerror(errno)); 759 return ZX_ERR_IO; 760 } 761 ssize_t res; 762 if ((res = write(fd_.get(), block_.get(), block_.len())) < 0) { 763 xprintf("write(%d, %p, %zu) failed: %s\n", fd_.get(), block_.get(), block_.len(), 764 strerror(errno)); 765 return ZX_ERR_IO; 766 } 767 if (static_cast<size_t>(res) != block_.len()) { 768 xprintf("short read: have %zd, need %zu\n", res, block_.len()); 769 return ZX_ERR_IO; 770 } 771 } 772 return ZX_OK; 773} 774 775} // namespace zxcrypt 776