blob: 272bc7321b78067717ea5a89a04ef0de1b10a6e1 [file] [log] [blame]
Mateusz Zalega356b8962021-08-10 17:27:15 +02001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17// This package implements a command line tool that creates dm-verity hash
18// images at a selected path, given an existing data image. The tool
19// outputs a Verity mapping table on success.
20//
21// For more information, see:
22// - source.monogon.dev/metropolis/pkg/verity
23// - https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
24package main
25
26import (
27 "fmt"
28 "io"
29 "log"
30 "os"
31
32 "source.monogon.dev/metropolis/pkg/verity"
33)
34
35// createHashImage creates a complete dm-verity hash image at
36// hashImagePath. Contents of the file at dataImagePath are accessed
37// read-only, hashed and written to the hash image in the process.
38// The verity superblock is written only if wsb is true.
39// It returns a string-convertible VerityMappingTable, or an error.
40func createHashImage(dataImagePath, hashImagePath string, wsb bool) (*verity.MappingTable, error) {
41 // Open the data image for reading.
42 dataImage, err := os.Open(dataImagePath)
43 if err != nil {
44 return nil, fmt.Errorf("while opening the data image: %w", err)
45 }
46 defer dataImage.Close()
47 // Create an empty hash image file.
48 hashImage, err := os.OpenFile(hashImagePath, os.O_RDWR|os.O_CREATE, 0644)
49 if err != nil {
50 return nil, fmt.Errorf("while opening the hash image for writing: %w", err)
51 }
52 defer hashImage.Close()
53
54 // Write hashImage contents. Start with initializing a verity encoder,
55 // seting hashImage as its output.
56 v, err := verity.NewEncoder(hashImage, wsb)
57 if err != nil {
58 return nil, fmt.Errorf("while initializing a verity encoder: %w", err)
59 }
60 // Hash the contents of dataImage, block by block.
61 _, err = io.Copy(v, dataImage)
62 if err != nil {
63 return nil, fmt.Errorf("while reading the data image: %w", err)
64 }
65 // The resulting hash tree won't be written until Close is called.
66 err = v.Close()
67 if err != nil {
68 return nil, fmt.Errorf("while writing the hash image: %w", err)
69 }
70
71 // Return an encoder-generated verity mapping table, containing the salt
72 // and the root hash.
73 mt, err := v.MappingTable(dataImagePath, hashImagePath)
74 if err != nil {
75 return nil, fmt.Errorf("while querying for the mapping table: %w", err)
76 }
77 return mt, nil
78}
79
80// usage prints program usage information.
81func usage(executable string) {
82 fmt.Println("Usage: ", executable, " <data image> <hash image>")
83}
84
85func main() {
86 if len(os.Args) != 3 {
87 usage(os.Args[0])
88 os.Exit(2)
89 }
90 dataImagePath := os.Args[1]
91 hashImagePath := os.Args[2]
92
93 // Attempt to build a new Verity hash Image at hashImagePath, based on
94 // the data image at dataImagePath. Include the Verity superblock.
95 mt, err := createHashImage(dataImagePath, hashImagePath, true)
96 if err != nil {
97 log.Fatal(err)
98 }
99 // Print a Device Mapper compatible mapping table.
100 fmt.Println(mt)
101}