github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/gadget/install/encrypt_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  // +build !nosecboot
     3  
     4  /*
     5   * Copyright (C) 2020 Canonical Ltd
     6   *
     7   * This program is free software: you can redistribute it and/or modify
     8   * it under the terms of the GNU General Public License version 3 as
     9   * published by the Free Software Foundation.
    10   *
    11   * This program is distributed in the hope that it will be useful,
    12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14   * GNU General Public License for more details.
    15   *
    16   * You should have received a copy of the GNU General Public License
    17   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18   *
    19   */
    20  
    21  package install_test
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"os"
    27  
    28  	. "gopkg.in/check.v1"
    29  
    30  	"github.com/snapcore/snapd/dirs"
    31  	"github.com/snapcore/snapd/gadget"
    32  	"github.com/snapcore/snapd/gadget/install"
    33  	"github.com/snapcore/snapd/secboot"
    34  	"github.com/snapcore/snapd/testutil"
    35  )
    36  
    37  type encryptSuite struct {
    38  	testutil.BaseTest
    39  
    40  	mockCryptsetup *testutil.MockCmd
    41  
    42  	mockedEncryptionKey secboot.EncryptionKey
    43  	mockedRecoveryKey   secboot.RecoveryKey
    44  }
    45  
    46  var _ = Suite(&encryptSuite{})
    47  
    48  var mockDeviceStructure = gadget.OnDiskStructure{
    49  	LaidOutStructure: gadget.LaidOutStructure{
    50  		VolumeStructure: &gadget.VolumeStructure{
    51  			Name: "Test structure",
    52  			Size: 0x100000,
    53  		},
    54  		StartOffset: 0,
    55  		Index:       1,
    56  	},
    57  	Node: "/dev/node1",
    58  }
    59  
    60  func (s *encryptSuite) SetUpTest(c *C) {
    61  	dirs.SetRootDir(c.MkDir())
    62  	c.Assert(os.MkdirAll(dirs.SnapRunDir, 0755), IsNil)
    63  
    64  	// create empty key to prevent blocking on lack of system entropy
    65  	s.mockedEncryptionKey = secboot.EncryptionKey{}
    66  	for i := range s.mockedEncryptionKey {
    67  		s.mockedEncryptionKey[i] = byte(i)
    68  	}
    69  	s.mockedRecoveryKey = secboot.RecoveryKey{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
    70  }
    71  
    72  func (s *encryptSuite) TestNewEncryptedDevice(c *C) {
    73  	for _, tc := range []struct {
    74  		mockedFormatErr error
    75  		mockedOpenErr   string
    76  		expectedErr     string
    77  	}{
    78  		{
    79  			mockedFormatErr: nil,
    80  			mockedOpenErr:   "",
    81  			expectedErr:     "",
    82  		},
    83  		{
    84  			mockedFormatErr: errors.New("format error"),
    85  			mockedOpenErr:   "",
    86  			expectedErr:     "cannot format encrypted device: format error",
    87  		},
    88  		{
    89  			mockedFormatErr: nil,
    90  			mockedOpenErr:   "open error",
    91  			expectedErr:     "cannot open encrypted device on /dev/node1: open error",
    92  		},
    93  	} {
    94  		script := ""
    95  		if tc.mockedOpenErr != "" {
    96  			script = fmt.Sprintf("echo '%s'>&2; exit 1", tc.mockedOpenErr)
    97  
    98  		}
    99  		s.mockCryptsetup = testutil.MockCommand(c, "cryptsetup", script)
   100  		s.AddCleanup(s.mockCryptsetup.Restore)
   101  
   102  		calls := 0
   103  		restore := install.MockSecbootFormatEncryptedDevice(func(key secboot.EncryptionKey, label, node string) error {
   104  			calls++
   105  			c.Assert(key, DeepEquals, s.mockedEncryptionKey)
   106  			c.Assert(label, Equals, "some-label-enc")
   107  			c.Assert(node, Equals, "/dev/node1")
   108  			return tc.mockedFormatErr
   109  		})
   110  		defer restore()
   111  
   112  		dev, err := install.NewEncryptedDevice(&mockDeviceStructure, s.mockedEncryptionKey, "some-label")
   113  		c.Assert(calls, Equals, 1)
   114  		if tc.expectedErr == "" {
   115  			c.Assert(err, IsNil)
   116  		} else {
   117  			c.Assert(err, ErrorMatches, tc.expectedErr)
   118  			continue
   119  		}
   120  		c.Assert(dev.Node, Equals, "/dev/mapper/some-label")
   121  
   122  		err = dev.Close()
   123  		c.Assert(err, IsNil)
   124  
   125  		c.Assert(s.mockCryptsetup.Calls(), DeepEquals, [][]string{
   126  			{"cryptsetup", "open", "--key-file", "-", "/dev/node1", "some-label"},
   127  			{"cryptsetup", "close", "some-label"},
   128  		})
   129  	}
   130  }
   131  
   132  func (s *encryptSuite) TestAddRecoveryKey(c *C) {
   133  	for _, tc := range []struct {
   134  		mockedAddErr error
   135  		expectedErr  string
   136  	}{
   137  		{mockedAddErr: nil, expectedErr: ""},
   138  		{mockedAddErr: errors.New("add key error"), expectedErr: "add key error"},
   139  	} {
   140  		s.mockCryptsetup = testutil.MockCommand(c, "cryptsetup", "")
   141  		s.AddCleanup(s.mockCryptsetup.Restore)
   142  
   143  		restore := install.MockSecbootFormatEncryptedDevice(func(key secboot.EncryptionKey, label, node string) error {
   144  			return nil
   145  		})
   146  		defer restore()
   147  
   148  		calls := 0
   149  		restore = install.MockSecbootAddRecoveryKey(func(key secboot.EncryptionKey, rkey secboot.RecoveryKey, node string) error {
   150  			calls++
   151  			c.Assert(key, DeepEquals, s.mockedEncryptionKey)
   152  			c.Assert(rkey, DeepEquals, s.mockedRecoveryKey)
   153  			c.Assert(node, Equals, "/dev/node1")
   154  			return tc.mockedAddErr
   155  		})
   156  		defer restore()
   157  
   158  		dev, err := install.NewEncryptedDevice(&mockDeviceStructure, s.mockedEncryptionKey, "some-label")
   159  		c.Assert(err, IsNil)
   160  
   161  		err = dev.AddRecoveryKey(s.mockedEncryptionKey, s.mockedRecoveryKey)
   162  		c.Assert(calls, Equals, 1)
   163  		if tc.expectedErr == "" {
   164  			c.Assert(err, IsNil)
   165  		} else {
   166  			c.Assert(err, ErrorMatches, tc.expectedErr)
   167  			continue
   168  		}
   169  
   170  		err = dev.Close()
   171  		c.Assert(err, IsNil)
   172  
   173  		c.Assert(s.mockCryptsetup.Calls(), DeepEquals, [][]string{
   174  			{"cryptsetup", "open", "--key-file", "-", "/dev/node1", "some-label"},
   175  			{"cryptsetup", "close", "some-label"},
   176  		})
   177  	}
   178  }