Skip to content

Commit

Permalink
Merge f927909 into 0c57b41
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Oct 30, 2019
2 parents 0c57b41 + f927909 commit f6288bc
Show file tree
Hide file tree
Showing 18 changed files with 476 additions and 25 deletions.
7 changes: 7 additions & 0 deletions package/yast2-storage-ng.changes
@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Wed Oct 30 09:55:48 UTC 2019 - Imobach Gonzalez Sosa <igonzalezsosa@suse.com>

- AutoYaST: add support to set the encryption method (related to
jsc#SLE-7376).
- 4.2.53

-------------------------------------------------------------------
Mon Oct 28 14:22:24 CET 2019 - aschnell@suse.com

Expand Down
2 changes: 1 addition & 1 deletion package/yast2-storage-ng.spec
Expand Up @@ -16,7 +16,7 @@
#

Name: yast2-storage-ng
Version: 4.2.52
Version: 4.2.53
Release: 0
Summary: YaST2 - Storage Configuration
License: GPL-2.0-only OR GPL-3.0-only
Expand Down
1 change: 1 addition & 0 deletions src/lib/y2storage/autoinst_issues.rb
Expand Up @@ -37,6 +37,7 @@ module AutoinstIssues
require "y2storage/autoinst_issues/could_not_calculate_boot"
require "y2storage/autoinst_issues/could_not_create_boot"
require "y2storage/autoinst_issues/exception"
require "y2storage/autoinst_issues/invalid_encryption"
require "y2storage/autoinst_issues/invalid_value"
require "y2storage/autoinst_issues/missing_reusable_device"
require "y2storage/autoinst_issues/missing_reusable_filesystem"
Expand Down
96 changes: 96 additions & 0 deletions src/lib/y2storage/autoinst_issues/invalid_encryption.rb
@@ -0,0 +1,96 @@
# Copyright (c) [2019] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "y2storage/autoinst_issues/issue"

module Y2Storage
module AutoinstIssues
# Represents a problem with encryption settings
#
# This issues are considered 'fatal' because they might lead to a situation
# where a device is not unencrypted as it was intended.
#
# @example The encryption method is not available in the running system
# hash = { "crypt_method" => :pervasive_luks2 }
# section = AutoinstProfile::PartitionSection.new_from_hashes(hash)
# issue = InvalidEncryption.new(section, :unavailable)
#
# @example The encryption method is unknown
# hash = { "crypt_method" => :foo }
# section = AutoinstProfile::PartitionSection.new_from_hashes(hash)
# issue = InvalidEncryption.new(section, :unknown)
#
# @example The encryption method is not suitable for the device
# hash = { "mount" => "/", "crypt_method" => :random_swap }
# section = AutoinstProfile::PartitionSection.new_from_hashes(hash)
# issue = InvalidEncryption.new(section, :unsuitable)
class InvalidEncryption < Issue
# @return [Symbol] Reason which causes the encryption to be invalid
attr_reader :reason

# @param section [#parent,#section_name] Section where it was detected (see {AutoinstProfile})
# @param reason [Symbol] Reason which casues the encryption to be invalid
# (:unknown when the method is unknown; :unavailable when the method is not available,
# :unsuitable when the method is not suitable for the device)
def initialize(section, reason)
textdomain "storage"

@section = section
@reason = reason
end

# Return problem severity
#
# @return [Symbol] :fatal
def severity
:fatal
end

# Returns the error message to be displayed
#
# @return [String] Error message
# @see Issue#message
def message
case reason
when :unavailable
# TRANSLATORS: 'crypt_method' is the name of the method to encrypt the device (like
# 'luks1' or 'random_swap').
format(
_("Encryption method '%{crypt_method}' is not available in this system."),
crypt_method: section.crypt_method
)
when :unknown
# TRANSLATORS: 'crypt_method' is the name of the method to encrypt the device (like
# 'luks1' or 'random_swap').
format(
_("'%{crypt_method}' is not a known encryption method."),
crypt_method: section.crypt_method
)
when :unsuitable
# TRANSLATORS: 'crypt_method' is the name of the method to encrypt the device (like
# 'luks1' or 'random_swap').
format(
_("'%{crypt_method}' is not a suitable method to encrypt the device."),
crypt_method: section.crypt_method
)
end
end
end
end
end
16 changes: 13 additions & 3 deletions src/lib/y2storage/autoinst_profile/partition_section.rb
Expand Up @@ -63,6 +63,7 @@ class PartitionSection < SectionWithAttributes
{ name: :size },
{ name: :crypt_fs },
{ name: :loop_fs },
{ name: :crypt_method },
{ name: :crypt_key },
{ name: :raid_name },
{ name: :raid_options },
Expand Down Expand Up @@ -92,7 +93,12 @@ def self.attributes
# @return [Boolean] whether the partition must be created or exists

# @!attribute crypt_fs
# @return [Boolean] whether the partition must be encrypted
# @return [Boolean] whether the partition must be encrypted.
# @deprecated Use #crypt_method instead.

# @!attribute crypt_method
# @return [Symbol,nil] encryption method (:luks1, :pervasive_luks2,
# :protected_swap, :random_swap or :secure_swap). See {Y2Storage::EncryptionMethod}.

# @!attribute crypt_key
# @return [String] encryption key
Expand Down Expand Up @@ -359,12 +365,16 @@ def init_lv_fields(lv)
@btrfs_name = name_for_btrfs(lv.filesystem)
end

DEFAULT_ENCRYPTION_METHOD = Y2Storage::EncryptionMethod.find(:luks1)
private_constant :DEFAULT_ENCRYPTION_METHOD

def init_encryption_fields(partition)
return unless partition.encrypted?

@crypt_fs = true
method = partition.encryption.method || DEFAULT_ENCRYPTION_METHOD
@loop_fs = true
@crypt_key = CRYPT_KEY_VALUE
@crypt_method = method.id
@crypt_key = CRYPT_KEY_VALUE if method.password_required?
end

def init_filesystem_fields(partition)
Expand Down
7 changes: 7 additions & 0 deletions src/lib/y2storage/encryption_method/base.rb
Expand Up @@ -98,6 +98,13 @@ def available?
true
end

# Determines whether a user provided password is required
#
# @return [Boolean]
def password_required?
true
end

# Whether the encryption method is useful only for swap
#
# Some encryption methods are mainly useful for encrypting swap disks since they produce a new key
Expand Down
5 changes: 5 additions & 0 deletions src/lib/y2storage/encryption_method/swap.rb
Expand Up @@ -44,6 +44,11 @@ def available?
File.exist?(key_file)
end

# @see Base#password_required?
def password_required?
false
end

# Encryption key file
#
# Each Swap process could use a different key file.
Expand Down
21 changes: 17 additions & 4 deletions src/lib/y2storage/planned/can_be_encrypted.rb
Expand Up @@ -37,9 +37,13 @@ module CanBeEncrypted
ENCRYPTION_OVERHEAD = DiskSize.MiB(2)
private_constant :ENCRYPTION_OVERHEAD

# @!attribute encryption_password
# @return [String, nil] password used to encrypt the device. If is nil,
# @!attribute encryption_method
# @return [String, nil] method used to encrypt the device. If is nil,
# it means the device will not be encrypted
secret_attr :encryption_method

# @!attribute encryption_password
# @return [String, nil] password used to encrypt the device.
secret_attr :encryption_password

# Initializations of the mixin, to be called from the class constructor.
Expand All @@ -49,7 +53,15 @@ def initialize_can_be_encrypted; end
#
# @return [Boolean]
def encrypt?
!encryption_password.nil?
!!(encryption_method || encryption_password)
end

# Determines whether the device can be ciphered using the given encryption method
#
# @param method [EncryptionMethod] Encryption method
# @return [Boolean]
def supported_encryption_method?(method)
!method.only_for_swap? || swap?
end

# Returns the (possibly encrypted) device to be used for the planned
Expand All @@ -66,7 +78,8 @@ def encrypt?
def final_device!(plain_device)
result = super
if create_encryption?
result = result.encrypt(password: encryption_password)
method = encryption_method || EncryptionMethod.find(:luks1)
result = result.encrypt(method: method, password: encryption_password)
log.info "Device encrypted. Returning the new device #{result.inspect}"
else
log.info "No need to encrypt. Returning the existing device #{result.inspect}"
Expand Down
59 changes: 54 additions & 5 deletions src/lib/y2storage/proposal/autoinst_drive_planner.rb
Expand Up @@ -63,9 +63,8 @@ def planned_devices(_drive)
# @param drive_section [AutoinstProfile::DriveSection] AutoYaST drive
# section containing the partition one
def configure_device(device, partition_section, drive_section)
add_device_attrs(device, partition_section)

configure_filesystem(device, partition_section, drive_section)
add_encryption_attrs(device, partition_section)
end

alias_method :device_config, :configure_device
Expand All @@ -82,12 +81,62 @@ def configure_filesystem(device, partition_section, drive_section)
configure_subvolumes(device, partition_section)
end

# Sets common devices attributes
DEFAULT_ENCRYPTION_METHOD = EncryptionMethod.find(:luks1)
private_constant :DEFAULT_ENCRYPTION_METHOD

# Sets encryption attributes
#
# @param device [Planned::Device] Planned device
# @param partition_section [AutoinstProfile::PartitionSection] AutoYaST specification
def add_encryption_attrs(device, partition_section)
return unless partition_section.crypt_fs || partition_section.crypt_method

device.encryption_method =
if partition_section.crypt_method
find_encryption_method(device, partition_section)
else
DEFAULT_ENCRYPTION_METHOD
end
return unless device.encryption_method&.password_required?

device.encryption_password = find_encryption_password(partition_section)
end

# Determines the encryption method for a partition section
#
# @param device [Planned::Device] Planned device
# @param partition_section [AutoinstProfile::PartitionSection] AutoYaST specification
def add_device_attrs(device, partition_section)
device.encryption_password = partition_section.crypt_key if partition_section.crypt_fs
# @return [EncryptionMethod,nil] Encryption method ID or nil if it could not be determined
def find_encryption_method(device, partition_section)
encryption_method = EncryptionMethod.find(partition_section.crypt_method)
error =
if encryption_method.nil?
:unknown
elsif !encryption_method.available?
:unavailable
elsif !device.supported_encryption_method?(encryption_method)
:unsuitable
end

if error
issues_list.add(:invalid_encryption, partition_section, error)
return
end

encryption_method
end

# Extracts the encryption password for a partition section
#
# Additionally it registers an issue if it is not found.
#
# @return [String,nil]
def find_encryption_password(partition_section)
if partition_section.crypt_key.nil? || partition_section.crypt_key.empty?
issues_list.add(:missing_value, partition_section, :crypt_key)
return
end
partition_section.crypt_key
end

# Sets common filesystem attributes
Expand Down
70 changes: 70 additions & 0 deletions test/y2storage/autoinst_issues/invalid_encryption_test.rb
@@ -0,0 +1,70 @@
# Copyright (c) [2019] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require_relative "../../spec_helper"
require "y2storage/autoinst_issues/invalid_encryption"
require "y2storage/autoinst_profile/partition_section"

describe Y2Storage::AutoinstIssues::InvalidEncryption do
subject(:issue) { described_class.new(section, reason) }

let(:crypt_method) { :luks1 }
let(:reason) { :unknown }
let(:section) do
instance_double(Y2Storage::AutoinstProfile::PartitionSection, crypt_method: crypt_method)
end

describe "#message" do
context "when method is unknown" do
let(:reason) { :unknown }
let(:crypt_method) { :foo }

it "warns about the method being unknown" do
message = issue.message
expect(message).to match(/'foo' is not a known/)
end
end

context "when method is unavailable" do
let(:reason) { :unavailable }
let(:crypt_method) { :pervasive_luks2 }

it "warns about the method not being available" do
message = issue.message
expect(message).to match(/'pervasive_luks2' is not available/)
end
end

context "when method is unsuitable" do
let(:reason) { :unsuitable }
let(:crypt_method) { :pervasive_luks2 }

it "warns about the method not being suitable" do
message = issue.message
expect(message).to match(/'pervasive_luks2' is not a suitable/)
end
end
end

describe "#severity" do
it "returns :fatal" do
expect(issue.severity).to eq(:fatal)
end
end
end

0 comments on commit f6288bc

Please sign in to comment.