Compare commits

...

No commits in common. "c8s" and "c10s" have entirely different histories.
c8s ... c10s

20 changed files with 1653 additions and 318 deletions

1
.fmf/version Normal file
View File

@ -0,0 +1 @@
1

11
.gitignore vendored
View File

@ -1 +1,10 @@
/volume_key-0.3.11.tar.xz
/.project
/volume_key-0.3.3.tar.xz
/volume_key-0.3.4.tar.xz
/volume_key-0.3.5.tar.xz
/volume_key-0.3.6.tar.xz
/volume_key-0.3.7.tar.xz
/volume_key-0.3.8.tar.xz
/volume_key-0.3.9.tar.xz
/volume_key-0.3.10.tar.xz
/volume_key-0.3.12.tar.xz

View File

@ -1,6 +1,6 @@
--- !Policy
product_versions:
- rhel-8
- rhel-10
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1.functional}
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}

15
plans/tier1.fmf Normal file
View File

@ -0,0 +1,15 @@
---
summary: Tier1 plan for volume_key
discover:
how: fmf
url: https://pkgs.devel.redhat.com/git/tests/volume_key
ref: master
filter: tier:1
execute:
how: tmt
adjust:
enabled: false
when: distro == centos-stream or distro == fedora

View File

@ -1 +1 @@
SHA512 (volume_key-0.3.11.tar.xz) = b9da00578b31c96231ebde55fd91c9aafbd663e541c560460fb6c3305e1a0e1fb3115a95682dc4713027d084e14ffa39d638653384a18d69f5dc892fc4855a97
SHA512 (volume_key-0.3.12.tar.xz) = d056154c9b9d23e4eb661946dd59ed97e116903a3afcff9d9e29258408082f33dcbb69958724143f6bf191a3da488a03b6c02af287790990ed6459e29d66553c

1
tests/.fmf/version Normal file
View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,16 @@
---
component: volume_key
summary: basic sanity test for volume_key utility
contact:
- Jan Blazek <jblazek@redhat.com>
- Jiri Kucera <jkucera@redhat.com>
description: basic sanity test for volume_key utility
require:
- volume_key
- cryptsetup
- nss-tools
- expect
- tcllib
test: ./runtest.sh
duration: 10m
tier: 1

View File

@ -0,0 +1,354 @@
#!/bin/bash
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# File: ./tests/Sanity/basic-sanity/runtest.sh
# Author: Jan Blazek <jblazek@redhat.com>
# Jiri Kucera <jkucera@redhat.com>
# Brief: Basic sanity test for volume_key utility
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2017-2020 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version.
#
# 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, see http://www.gnu.org/licenses/.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_TESTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
# Include Beaker environment
. /usr/bin/rhts-environment.sh || exit 1
. /usr/share/beakerlib/beakerlib.sh || exit 1
# Include utils
. ${_TESTDIR}/../../utils/utils.sh || {
echo "${_TESTDIR}/../../utils/utils.sh cannot be included." >&2
exit 1
}
# Include test settings:
. ${_TESTDIR}/../../settings/environment.sh || {
errmsg "${_TESTDIR}/../../settings/environment.sh cannot be included."
exit 1
}
TEST="${TEST:-/CoreOS/volume_key/tests/Sanity/basic-sanity}"
TESTVERSION="${TESTVERSION:-1.0}"
PACKAGES="${PACKAGES:-volume_key}"
REQUIRES="${REQUIRES:-cryptsetup nss-tools expect tcllib}"
_GNUPG_DIR="${HOME}/.gnupg"
_IMAGE="${_IMAGE:-image}"
_IMAGE_IMG="${_IMAGE}.img"
_PACKET="${_PACKET:-packet}"
_NEW_PACKET="${_NEW_PACKET:-new-packet}"
_PACKET_ASYM="${_PACKET_ASYM:-packet-asym}"
_NEW_PACKET_ASYM="${_NEW_PACKET_ASYM:-new-packet-asym}"
_ESCROW="${_ESCROW:-escrow}"
_ESCROW_PEM="${_ESCROW}.pem"
_NSSDB="${_NSSDB:-nssdb}"
_LUKS_PASS="${_LUKS_PASS:-lukspass}"
_PACKET_PASS="${_PACKET_PASS:-packetpass}"
_NEW_PACKET_PASS="${_NEW_PACKET_PASS:-newpacketpass}"
_CERT_PASS="${_CERT_PASS:-certpass}"
_NEW_LUKS_PASS="${_NEW_LUKS_PASS:-newlukspass}"
_NEW_LUKS_PASS_ASYM="${_NEW_LUKS_PASS_ASYM:-newlukspass-asym}"
_TEMP_DIR=""
_VOLUME=""
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~ Setup
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function Setup() {
LANG=C
LC_ALL=C
export EXPECT_SCRIPTS_PATH="${SCRIPTDIR}"
rlAssertRpm --all || return $?
if [[ -d "${_GNUPG_DIR}" ]]; then
rlFileBackup "${_GNUPG_DIR}" || return $?
AtCleanup rlFileRestore
else
AtCleanup Cleanup_RemoveGnuPG
fi
rlRun CreateTemporaryDirectory || return $?
_TEMP_DIR="${Result}"
AtCleanup Cleanup_RemoveTemporaryDirectory
PushDir "${_TEMP_DIR}" || return $?
AtCleanup PopDir
CreateEncryptedVolume \
--image "${_IMAGE_IMG}" \
--password "${_LUKS_PASS}" \
${USE_LOSETUP:+--with-losetup} \
|| return $?
_VOLUME="${Result}"
AtCleanup Cleanup_DestroyVolume
CreateCertificate --name "${_ESCROW}" || return $?
SetupNSSDatabase --dest "${_TEMP_DIR}/${_NSSDB}" \
--cert-name "${_ESCROW}" --password "${_CERT_PASS}"
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~ Cleanup
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function Cleanup_RemoveGnuPG() {
RunCmd rm -rfv "${_GNUPG_DIR}"
}
function Cleanup_RemoveTemporaryDirectory() {
RunCmd rm -rfv "${_TEMP_DIR}"
}
function Cleanup_DestroyVolume() {
if [[ "${USE_LOSETUP:+yes}" == "yes" ]]; then
RunCmd losetup -d "${_VOLUME}"
fi
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~ Tests
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function TestVolumeKeySave() {
RunCmdViaExpect
Command volume_key
Command --save "${_VOLUME}" --output-format=passphrase -o "${_PACKET}"
Input --lukspass "${_LUKS_PASS}"
Input --packetpass "${_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun
}
AddTest TestVolumeKeySave "save"
function TestVolumeKeyRestore() {
rlAssertExists "${_PACKET}" || return $?
ClearGpgAgentsCache
RunCmdViaExpect
Command volume_key --restore "${_VOLUME}" "${_PACKET}"
Input --lukspass "${_NEW_LUKS_PASS}"
Input --packetpass "${_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun || return $?
RunCmdViaExpect
Command cryptsetup luksOpen "${_VOLUME}" "${_IMAGE}"
Input --password "${_NEW_LUKS_PASS}"
FinishRun || return $?
RunCmd ls -la /dev/mapper
rlAssertExists "/dev/mapper/${_IMAGE}"
RunCmd cryptsetup luksClose "${_IMAGE}"
}
AddTest TestVolumeKeyRestore "restore"
function TestVolumeKeySetupVolume() {
rlAssertExists "${_PACKET}" || return $?
ClearGpgAgentsCache
RunCmdViaExpect
Command volume_key --setup-volume "${_VOLUME}" "${_PACKET}" "${_IMAGE}"
Input --packetpass "${_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun || return $?
RunCmd ls -la /dev/mapper
rlAssertExists "/dev/mapper/${_IMAGE}"
RunCmd cryptsetup luksClose "${_IMAGE}"
}
AddTest TestVolumeKeySetupVolume "setup-volume"
function TestVolumeKeyReencrypt() {
rlAssertExists "${_PACKET}" || return $?
ClearGpgAgentsCache
RunCmdViaExpect
Command volume_key --reencrypt "${_PACKET}" -o "${_NEW_PACKET}"
Input --packetpass "${_PACKET_PASS}"
Input --newpacketpass "${_NEW_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun || return $?
ClearGpgAgentsCache
RunCmdViaExpect
Command volume_key --setup-volume "${_VOLUME}" "${_NEW_PACKET}" "${_IMAGE}"
Input --packetpass "${_NEW_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun || return $?
RunCmd ls -la /dev/mapper
rlAssertExists "/dev/mapper/${_IMAGE}"
RunCmd cryptsetup luksClose "${_IMAGE}"
}
AddTest TestVolumeKeyReencrypt "reencrypt"
function TestVolumeKeyDump() {
local __uuid=""
rlAssertExists "${_PACKET}" || return $?
ClearGpgAgentsCache
RunCmdViaExpect
rlRunOptions -s
Command volume_key --dump "${_PACKET}"
Input --packetpass "${_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun || return $?
__uuid="$(blkid -o value -s UUID "${_VOLUME}")"
rlAssertGrep '^Packet format:\W+Passphrase-encrypted' "${rlRun_LOG}" -E
rlAssertGrep '^Volume format:\W+crypt_LUKS' "${rlRun_LOG}" -E
rlAssertGrep "^Volume UUID:\W+${__uuid}" "${rlRun_LOG}" -E
rlAssertGrep "^Volume path:\W+${_VOLUME}" "${rlRun_LOG}" -E
}
AddTest TestVolumeKeyDump "dump"
function TestVolumeKeySecrets() {
rlAssertExists "${_PACKET}" || return $?
ClearGpgAgentsCache
RunCmdViaExpect
rlRunOptions -s
Command volume_key --secrets "${_PACKET}"
Input --packetpass "${_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun || return $?
rlAssertGrep 'Data encryption key:\W+[0-9A-F]+' "${rlRun_LOG}" -E
}
AddTest TestVolumeKeySecrets "secrets"
function TestVolumeKeySaveAsymmetric() {
RunCmdViaExpect
Command volume_key
Command --save "${_VOLUME}" --output-format=asymmetric
Command -c "${_ESCROW_PEM}" -o "${_PACKET_ASYM}"
Input --lukspass "${_LUKS_PASS}"
FinishRun
}
AddTest TestVolumeKeySaveAsymmetric "save asymmetric"
function TestVolumeKeyRestoreAsymmetric() {
rlAssertExists "${_PACKET_ASYM}" || return $?
RunCmdViaExpect
Command volume_key --restore "${_VOLUME}" "${_PACKET_ASYM}" -d "${_NSSDB}"
Input --certpass "${_CERT_PASS}"
Input --lukspass "${_NEW_LUKS_PASS_ASYM}"
FinishRun || return $?
RunCmdViaExpect
Command cryptsetup luksOpen "${_VOLUME}" "${_IMAGE}"
Input --password "${_NEW_LUKS_PASS_ASYM}"
FinishRun || return $?
RunCmd ls -la /dev/mapper
rlAssertExists "/dev/mapper/${_IMAGE}"
RunCmd cryptsetup luksClose "${_IMAGE}"
}
AddTest TestVolumeKeyRestoreAsymmetric "restore asymmetric"
function TestVolumeKeySetupVolumeAsymmetric() {
rlAssertExists "${_PACKET_ASYM}" || return $?
RunCmdViaExpect
Command volume_key
Command --setup-volume "${_VOLUME}" "${_PACKET_ASYM}" "${_IMAGE}"
Command -d "${_NSSDB}"
Input --certpass "${_CERT_PASS}"
FinishRun || return $?
RunCmd ls -la /dev/mapper
rlAssertExists "/dev/mapper/${_IMAGE}"
RunCmd cryptsetup luksClose "${_IMAGE}"
}
AddTest TestVolumeKeySetupVolumeAsymmetric "setup-volume asymmetric"
function TestVolumeKeyReencryptAsymmetric() {
rlAssertExists "${_PACKET_ASYM}" || return $?
ClearGpgAgentsCache
RunCmdViaExpect
Command volume_key --reencrypt
Command -d "${_NSSDB}" "${_PACKET_ASYM}" -o "${_NEW_PACKET_ASYM}"
Input --certpass "${_CERT_PASS}"
Input --newpacketpass "${_NEW_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun || return $?
ClearGpgAgentsCache
RunCmdViaExpect
Command volume_key
Command --setup-volume "${_VOLUME}" "${_NEW_PACKET_ASYM}" "${_IMAGE}"
Input --packetpass "${_NEW_PACKET_PASS}"
Input ${USING_PINENTRY:+--pinentry}
FinishRun || return $?
RunCmd ls -la /dev/mapper
rlAssertExists "/dev/mapper/${_IMAGE}"
RunCmd cryptsetup luksClose "${_IMAGE}"
}
AddTest TestVolumeKeyReencryptAsymmetric "reencrypt asymmetric"
function TestVolumeKeyDumpAsymmetric() {
local __uuid=""
rlAssertExists "${_PACKET_ASYM}" || return $?
RunCmdViaExpect
rlRunOptions -s
Command volume_key --dump "${_PACKET_ASYM}" -d "${_NSSDB}"
Input --certpass "${_CERT_PASS}"
FinishRun || return $?
__uuid="$(blkid -o value -s UUID "${_VOLUME}")"
rlAssertGrep '^Packet format:\W+Public key-encrypted' "${rlRun_LOG}" -E
rlAssertGrep '^Volume format:\W+crypt_LUKS' "${rlRun_LOG}" -E
rlAssertGrep "^Volume UUID:\W+${__uuid}" "${rlRun_LOG}" -E
rlAssertGrep "^Volume path:\W+${_VOLUME}" "${rlRun_LOG}" -E
}
AddTest TestVolumeKeyDumpAsymmetric "dump asymmetric"
function TestVolumeKeySecretsAsymmetric() {
rlAssertExists "${_PACKET_ASYM}" || return $?
RunCmdViaExpect
rlRunOptions -s
Command volume_key --secrets "${_PACKET_ASYM}" -d "${_NSSDB}"
Input --certpass "${_CERT_PASS}"
FinishRun || return $?
rlAssertGrep 'Data encryption key:\W+[0-9A-F]+' "${rlRun_LOG}" -E
}
AddTest TestVolumeKeySecretsAsymmetric "secrets asymmetric"
RunTest

View File

@ -0,0 +1,28 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# File: ./tests/settings/environment.sh
# Author: Jiri Kucera <jkucera@redhat.com>
# Brief: Environment variables with distribution specific values
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2020 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version.
#
# 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, see http://www.gnu.org/licenses/.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export USE_LOSETUP="${USE_LOSETUP:-}"
export USING_PINENTRY="${USING_PINENTRY:-}"
export CLEAR_GPG_AGENTS_CACHE="${CLEAR_GPG_AGENTS_CACHE:-1}"

14
tests/tests.yml Normal file
View File

@ -0,0 +1,14 @@
---
- hosts: localhost
roles:
- role: standard-test-beakerlib
tags:
- classic
- container
fmf_filter: "tier: 1"
required_packages:
- volume_key
- cryptsetup
- expect
- tcllib
- nss-tools

39
tests/utils/common.tcl Normal file
View File

@ -0,0 +1,39 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# File: ./tests/utils/common.tcl
# Author: Jiri Kucera <jkucera@redhat.com>
# Brief: Common utilities for expect scripts
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2020 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version.
#
# 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, see http://www.gnu.org/licenses/.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
proc oneof {l1 l2} {
foreach x $l1 {
if {$x in $l2} {
return 1
}
}
return 0
}
proc verify_password {password} {
if {$password == ""} {
return -code error "password required!"
}
}

66
tests/utils/cryptsetup.exp Executable file
View File

@ -0,0 +1,66 @@
#!/usr/bin/expect -f
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# File: ./tests/utils/cryptsetup.exp
# Author: Jiri Kucera <jkucera@redhat.com>
# Brief: Expect wrapper around cryptsetup
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2020 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version.
#
# 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, see http://www.gnu.org/licenses/.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package require cmdline
source [file join [file dirname [info script]] "common.tcl"]
set options {
{password.arg "" "Password required by some cryptsetup actions"}
}
set usage "\[options\] -- cryptsetup_options\noptions:"
if {[catch {
array set params [::cmdline::getoptions argv $options $usage]
} result]} {
if {$::errorCode eq {CMDLINE USAGE}} {
puts $result
exit 0
}
puts $::errorCode
puts $::errorInfo
exit 1
}
set password $params(password)
eval spawn cryptsetup $::argv
if {"luksFormat" in $::argv} {
verify_password $password
expect -re "^Are you sure.*:"
send -- "YES\r"
expect -re "Enter( LUKS)? passphrase.*"
send -- "$password\r"
expect -re "Verify passphrase.*"
send -- "$password\r"
expect eof
} elseif {"luksOpen" in $::argv} {
verify_password $password
expect -re "Enter passphrase for.*"
send -- "$password\r"
expect eof
}

508
tests/utils/rlwrap.sh Normal file
View File

@ -0,0 +1,508 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# File: ./tests/utils/rlwrap.sh
# Author: Jiri Kucera <jkucera@redhat.com>
# Brief: Wrapper around beakerlib (rlX) functions
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2020 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version.
#
# 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, see http://www.gnu.org/licenses/.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
##
# Result, ResultA, ResultB
#
# If a function has an output, it is stored inside these variables.
Result=""
ResultA=""
ResultB=""
# Internal variables used by RunCmdViaExpect family of functions.
_rlwrap_expect_script_path=""
declare -ag _rlwrap_rlRun_options=()
declare -ag _rlwrap_expect_options=()
_rlwrap_expect_script=""
_rlwrap_expect_script_scommand=""
declare -ag _rlwrap_expect_script_command_args=()
declare -ag _rlwrap_expect_script_input_args=()
_rlwrap_rlRun_status="0"
_rlwrap_rlRun_comment=""
# Internal variables used by RunTest family of functions.
declare -ag _CleanupActions=()
declare -ag _Tests=()
##
# errmsg ERRMSG
#
# ERRMSG
# error message
#
# Print ERRMSG to standard error output.
function errmsg() {
echo "$1" >&2
}
##
# required_options OPTION_LIST
#
# OPTION_LIST
# a list of option names (without --)
#
# For every X from OPTION_LIST, test if --$X was specified by checking that
# __${X//-/_} is not empty.
function required_options() {
local __optvar=""
while [[ $# -gt 0 ]]; do
__optvar="__${1//-/_}"
if [[ -z "${!__optvar}" ]]; then
errmsg "${FUNCTION[1]}: Missing required option: --$1"
return 1
fi
shift
done
}
##
# invalid_argument ARG_NAME
#
# ARG_NAME
# argument name
#
# Report to standard error output that ARG_NAME is not a valid argument and
# return 1.
function invalid_argument() {
errmsg "${FUNCTION[1]}: Invalid argument '$1'."
return 1
}
##
# Concat ARGS
#
# ARGS
# list of arguments
#
# Make a string by concatenating all arguments from ARGS. Useful for creating
# long comments for rlRun.
function Concat() {
echo "$*"
}
##
# RunCmd COMMAND [COMMAND_ARGS]
#
# COMMAND
# command that should be run
# COMMAND_ARGS
# command arguments
#
# Shorthand for RunCmdX -- COMMAND COMMAND_ARGS.
function RunCmd() {
RunCmdX -- "$@"
}
##
# RunCmdX [-t] [-l] [-c] [-s] [STATUS] [COMMENT] [--] COMMAND [COMMAND_ARGS]
#
# -t, -l, -c, -s
# see rlRun
# STATUS
# see rlRun
# COMMENT
# see rlRun
# --
# options-command delimiter
# COMMAND
# command that should be run
# COMMAND_ARGS
# command arguments
#
# Wrapper around beakerlib's rlRun that allows COMMAND and its arguments to be
# passed separately and not as one long string.
function RunCmdX() {
local __tflag=""
local __lflag=""
local __cflag=""
local __sflag=""
local __command=""
local __status="0"
local __comment=""
# Handle short options:
while [[ $# -gt 0 ]]; do
case "$1" in
-t) __tflag="$1" ;;
-l) __lflag="$1" ;;
-c) __cflag="$1" ;;
-s) __sflag="$1" ;;
*) break ;;
esac
shift
done
# First positional argument before -- is expected status code:
if [[ -n "${1:-}" ]] && [[ "$1" != "--" ]]; then
__status="$1"
shift
fi
# Second positional argument before -- is comment:
if [[ -n "${1:-}" ]] && [[ "$1" != "--" ]]; then
__comment="$1"
shift
fi
# Consume options-command delimiter:
if [[ "${1:-}" == "--" ]]; then
shift
fi
# Command name is required:
if [[ -z "${1:-}" ]]; then
errmsg "Expected command."
return 1
fi
__command="$1"; shift
# The rest of options are command arguments:
while [[ $# -gt 0 ]]; do
__command="${__command} $1"
shift
done
# Let the game begin:
rlRun ${__tflag} ${__lflag} ${__cflag} ${__sflag} \
"${__command}" "${__status}" "${__comment}"
}
##
# RunCmdViaExpect
#
# Starts a specification of command that should be run via expect. This is
# handy for interactive commands. General usage is
#
# RunCmdViaExpect
# Path ${ScriptsDir}
# rlRunOptions -s
# ExpectOptions -f
# Command cryptsetup luksFormat ${VOLUME}
# Input --password ${PASSWD}
# Status 0
# Comment "Format ${VOLUME}"
# FinishRun || return $?
#
# In the example above, Path specifies the directory where the expect script
# is located. If it is omitted, EXPECT_SCRIPTS_PATH environment variable is
# read. If EXPECT_SCRIPTS_PATH is not set, `.` is used.
#
# rlRunOptions are options for rlRun, like -s and -t (see beakerlib manual).
#
# ExpectOptions are options for expect tool or Tcl interpreter, not for the
# script.
#
# Command is a command together with its arguments that will be run via expect.
# The first command argument, the command itself, is used as a name of expect
# script so in the example above the name of expect script will be
# cryptsetup.exp. This script must exist in directory specified by Path. The
# rest of Command arguments will be passed to the end of this script's command
# line and it is up to script's implementation what happen to them.
#
# Input gather arguments that specify input data that are feed to command by
# expect tool when they are asked for.
#
# Input, Command, ExpectOptions, and rlRunOptions work in accumulative way.
# That is, you can write `Command cryptsetup luksFormat ${VOLUME}` as a two
# Command calls, e.g. `Command cryptsetup` and `luksFormat ${VOLUME}`. This
# allow to split long commands accross multiple lines without using backslash
# character, which has the benefit of writing comments for particular command
# options.
#
# Status is the expected status/return code (default is 0).
#
# Comment is the comment as described in rlRun documentation. The default
# comment is a string made from arguments of Command separated by spaces.
#
# FinishRun makes a final arguments for rlRun and execute it. In our case, the
# rlRun call will look like this
#
# rlRun -s "${ScriptsDir}/cryptsetup.exp -f -- --password ${PASSWD} --
# luksFormat ${VOLUME}" 0 "Format ${VOLUME}"
#
# The return code of rlRun is the return code of FinishRun. To parse its
# command line, cryptsetup.exp uses cmdline package from tcllib.
function RunCmdViaExpect() {
_rlwrap_expect_script_path="${EXPECT_SCRIPTS_PATH:-.}"
_rlwrap_rlRun_options=()
_rlwrap_expect_options=()
_rlwrap_expect_script=""
_rlwrap_expect_script_scommand=""
_rlwrap_expect_script_command_args=()
_rlwrap_expect_script_input_args=()
_rlwrap_rlRun_status="0"
_rlwrap_rlRun_comment=""
alias Path=_rlwrap_Path
alias rlRunOptions=_rlwrap_rlRunOptions
alias ExpectOptions=_rlwrap_ExpectOptions
alias Command=_rlwrap_Command
alias Input=_rlwrap_Input
alias Status=_rlwrap_Status
alias Comment=_rlwrap_Comment
}
##
# _rlwrap_Path [PATH]
#
# PATH
# PATH to script directory
#
# See Path in RunCmdViaExpect.
function _rlwrap_Path() {
if [[ $# -gt 0 ]]; then
_rlwrap_expect_script_path="${1}"
fi
}
##
# _rlwrap_rlRunOptions [OPTIONS]
#
# OPTIONS
# options for rlRun
#
# See rlRunOptions in RunCmdViaExpect.
function _rlwrap_rlRunOptions() {
_rlwrap_rlRun_options+=( "$@" )
}
##
# _rlwrap_ExpectOptions [OPTIONS]
#
# OPTIONS
# options for expect tool
#
# See ExpectOptions in RunCmdViaExpect.
function _rlwrap_ExpectOptions() {
_rlwrap_expect_options+=( "$@" )
}
##
# _rlwrap_Command [COMMAND_OR_OPTION] [COMMAND_OPTIONS]
#
# COMMAND_OR_OPTION
# command name or option (depending on a number of Command invocations)
# COMMAND_OPTIONS
# command options
#
# See Command in RunCmdViaExpect.
function _rlwrap_Command() {
if [[ -z "${_rlwrap_expect_script}" ]]; then
if [[ -n "${1:-}" ]]; then
_rlwrap_expect_script="${1}.exp"
_rlwrap_expect_script_scommand="${1}"
shift
fi
fi
if [[ $# -gt 0 ]]; then
_rlwrap_expect_script_command_args+=( "$@" )
_rlwrap_expect_script_scommand="${_rlwrap_expect_script_scommand} $*"
fi
}
##
# _rlwrap_Input [OPTIONS]
#
# OPTIONS
# options for expect script that are used for passing input values to
# commands that are run from within the script
#
# See Input in RunCmdViaExpect.
function _rlwrap_Input() {
_rlwrap_expect_script_input_args+=( "$@" )
}
##
# _rlwrap_Status [STATUS_CODE]
#
# STATUS_CODE
# expected status/return code of expect script
#
# See Status in RunCmdViaExpect.
function _rlwrap_Status() {
if [[ $# -gt 0 ]]; then
_rlwrap_rlRun_status="${1}"
fi
}
##
# _rlwrap_Comment [COMMENT]
#
# COMMENT
# comment to be passed to rlRun
#
# See Comment in RunCmdViaExpect.
function _rlwrap_Comment() {
if [[ $# -gt 0 ]]; then
_rlwrap_rlRun_comment="${1}"
fi
}
##
# FinishRun
#
# See RunCmdViaExpect.
function FinishRun() {
local __command=""
unalias Path
unalias rlRunOptions
unalias ExpectOptions
unalias Command
unalias Input
unalias Status
unalias Comment
if [[ -z "${_rlwrap_expect_script}" ]]; then
errmsg "RunCmdViaExpect: Missing name of expect script!"
errmsg "| The name of expect script is deduced from the first"
errmsg "| argument given to Command."
return 1
fi
if [[ -z "${_rlwrap_rlRun_comment}" ]]; then
_rlwrap_rlRun_comment="${_rlwrap_expect_script_scommand}"
fi
__command="${_rlwrap_expect_script_path}/${_rlwrap_expect_script}"
__command="${__command} ${_rlwrap_expect_options[*]} --"
__command="${__command} ${_rlwrap_expect_script_input_args[*]} --"
__command="${__command} ${_rlwrap_expect_script_command_args[*]}"
rlRun "${_rlwrap_rlRun_options[@]}" "${__command}" \
"${_rlwrap_rlRun_status}" "${_rlwrap_rlRun_comment}"
}
##
# CreateTemporaryDirectory
#
# Create a temporary directory and store its path to Result.
function CreateTemporaryDirectory() {
Result="$(mktemp -d)"
}
##
# PushDir DIRECTORY
#
# DIRECTORY
# path to directory
#
# Perform `rlRun pushd DIRECTORY`.
function PushDir() {
RunCmd pushd "\"$1\""
}
##
# PopDir
#
# Perform `rlRun popd`.
function PopDir() {
RunCmd popd
}
##
# AtCleanup COMMAND
#
# COMMAND
# cleanup action as a command
#
# Insert COMMAND to the beginning of the list of cleanup actions.
function AtCleanup() {
_CleanupActions=( "$1" "${_CleanupActions[@]}" )
}
##
# AddTest TESTFUNC [DESCRIPTION]
#
# TESTFUNC
# function that performs the test
# DESCRIPTION
# test description
#
# Add test to the list of tests.
function AddTest() {
_Tests+=( "$1=${2:-}" )
}
##
# DoSetup
#
# Invoke Setup function and return its status code. Setup must be defined
# before.
function DoSetup() {
local __status=0
rlPhaseStartSetup
if [[ "$(LC_ALL=C type -t Setup)" != "function" ]]; then
rlFail "Function 'Setup' is not defined. Please, define it."
else
Setup
fi
__status=$?
rlPhaseEnd
return ${__status}
}
##
# DoTests
#
# Run all tests from the tests list.
function DoTests() {
for __testspec in "${_Tests[@]}"; do
# __testspec has the format 'testfunc=test description':
rlPhaseStartTest "${__testspec#*=}"
"${__testspec%%=*}" || :
rlPhaseEnd
done
}
##
# DoCleanup
#
# Run all registered cleanup actions in the reverse order than they were
# registered by AtCleanup.
function DoCleanup() {
rlPhaseStartCleanup
for __action in "${_CleanupActions[@]}"; do
"${__action}" || :
done
rlPhaseEnd
}
##
# RunTest
#
# Test runner entry point. Perform setup, run all tests, and perform cleanup.
function RunTest() {
rlJournalStart
DoSetup && DoTests
DoCleanup
rlJournalPrintText
rlJournalEnd
}

195
tests/utils/utils.sh Normal file
View File

@ -0,0 +1,195 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# File: ./tests/utils/utils.sh
# Author: Jiri Kucera <jkucera@redhat.com>
# Brief: Common shell utilities that helps test volume_key
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2020 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version.
#
# 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, see http://www.gnu.org/licenses/.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
##
# SCRIPTDIR
#
# Path to the directory with auxiliary scripts.
SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
# Include beakerlib wrapper:
. "${SCRIPTDIR}/rlwrap.sh" || {
echo "${SCRIPTDIR}/rlwrap.sh cannot be included." >&2
exit 1
}
##
# ClearGpgAgentsCache
#
# If CLEAR_GPG_AGENTS_CACHE is set, clear gpg-agent's password cache.
function ClearGpgAgentsCache() {
local __pid=""
if [[ "${CLEAR_GPG_AGENTS_CACHE:-}" == "1" ]] \
&& __pid="$(pidof -s gpg-agent)"
then
kill -s SIGHUP ${__pid} || :
fi
}
##
# CreateEncryptedVolume --image IMAGE --password PASS [--with-losetup]
#
# --image IMAGE
# path to image file from which volume is created; IMAGE is created by
# dd so it should not to point to an existing file
# --password PASS
# password needed to encrypt the volume
# --with-losetup
# create a volume as loop device
#
# Create encrypted volume from IMAGE (use PASS for the encryption). The name of
# created volume is stored to Result.
function CreateEncryptedVolume() {
local __image=""
local __volume=""
local __password=""
local __with_losetup=""
while [[ $# -gt 0 ]]; do
case "$1" in
--image) shift; __image="$1" ;;
--password) shift; __password="$1" ;;
--with-losetup) __with_losetup="yes" ;;
*) invalid_argument "$1"; return $? ;;
esac
shift
done
required_options image password || return $?
RunCmd dd if=/dev/zero of="${__image}" bs=1M count=256 || return $?
__volume="${__image}"
if [[ "${__with_losetup}" == "yes" ]]; then
RunCmd losetup -v -f "${__image}" || return $?
__volume="$(
set -o pipefail
losetup -a | grep "${__image}" | cut -d: -f1
)" || return $?
fi
RunCmdViaExpect
Command cryptsetup luksFormat "${__volume}"
Input --password "${__password}"
FinishRun || return $?
Result="${__volume}"
}
##
# CreateCertificate --name NAME [--rsa-bits BITS]
#
# --name NAME
# certificate name
# --rsa-bits BITS
# RSA bits (default: 1024)
#
# Create NAME.key, NAME.cert, and NAME.pem inside current working directory.
function CreateCertificate() {
local __name=""
local __rsa_bits=1024
local __key=""
local __cert=""
local __pem=""
local __subject=""
while [[ $# -gt 0 ]]; do
case "$1" in
--name) shift; __name="$1" ;;
--rsa-bits) shift; __rsa_bits="$1" ;;
*) invalid_argument "$1"; return $? ;;
esac
shift
done
required_options name || return $?
__key="${__name}.key"
__cert="${__name}.cert"
__pem="${__name}.pem"
RunCmd openssl genrsa ${__rsa_bits} \> "${__key}" || return $?
__subject="/C=XX/ST=FooState/L=FooLocality/O=FooOrg/OU=FooOrgUnit"
__subject="${__subject}/CN=John/SN=Doe/emailAddress=jdoe@foo.bar"
RunCmd openssl req -new -x509 -nodes -sha1 -days 365 \
-key "${__key}" -subj "'${__subject}'" \> "${__cert}" \
|| return $?
RunCmd cat "${__cert}" "${__key}" \> "${__pem}"
}
##
# SetupNSSDatabase --dest DEST --cert-name NAME --password PASS
#
# --dest DEST
# path to directory that become NSS database
# --cert-name NAME
# the name of the certificate
# --password PASS
# a password (common for certificate and for NSS database)
#
# Create and initialize NSS database DEST with certificate NAME and secure it
# with password PASS.
function SetupNSSDatabase() {
local __dest=""
local __cert_name=""
local __password=""
local __pwdfile=""
local __pem=""
local __p12=""
while [[ $# -gt 0 ]]; do
case "$1" in
--dest) shift; __dest="$1" ;;
--cert-name) shift; __cert_name="$1" ;;
--password) shift; __password="$1" ;;
*) invalid_argument "$1"; return $? ;;
esac
shift
done
required_options dest cert-name password || return $?
RunCmd mkdir -p "${__dest}" || return $?
__pwdfile="$(mktemp "./pwdfileXXXXX")" || return $?
__pem="${__cert_name}.pem"
__p12="${__cert_name}.p12"
RunCmd echo "${__password}" \> "${__pwdfile}" || return $?
RunCmd certutil -N -d "${__dest}" -f "${__pwdfile}" || return $?
RunCmd openssl pkcs12 -export -in "${__pem}" -out "${__p12}" \
-name "${__cert-name}" -password "pass:${__password}" \
|| return $?
RunCmd pk12util -i "${__p12}" -d "${__dest}" \
-K "${__password}" -W "${__password}"
}

143
tests/utils/volume_key.exp Executable file
View File

@ -0,0 +1,143 @@
#!/usr/bin/expect -f
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# File: ./tests/utils/volume_key.exp
# Author: Jiri Kucera <jkucera@redhat.com>
# Brief: Expect wrapper around volume_key
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2020 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version.
#
# 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, see http://www.gnu.org/licenses/.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package require cmdline
source [file join [file dirname [info script]] "common.tcl"]
set options {
{certpass.arg "" "Password for certificate"}
{lukspass.arg "" "Password for LUKS encryption/decryption"}
{packetpass.arg "" "Password for escrow packet encryption/decryption"}
{newpacketpass.arg "" "New password for escrow packet reencryption"}
{pinentry "gpg-agent may ask for password via pinentry"}
}
set usage "\[options\] -- volume_key_options\noptions:"
if {[catch {
array set params [::cmdline::getoptions argv $options $usage]
} result]} {
if {$::errorCode eq {CMDLINE USAGE}} {
puts $result
exit 0
}
puts $::errorCode
puts $::errorInfo
exit 1
}
set certpass $params(certpass)
set lukspass $params(lukspass)
set packetpass $params(packetpass)
set newpacketpass $params(newpacketpass)
set pinentry $params(pinentry)
proc prompt_cert_password {password} {
verify_password $password
expect -re "Enter password for.*"
sleep 1
send -- "$password\r"
}
proc prompt_luks_password {password} {
verify_password $password
expect -re "Passphrase for.*"
sleep 1
send -- "$password\r"
}
proc prompt_new_luks_password {password} {
verify_password $password
expect -re "New passphrase for.*"
sleep 1
send -- "$password\r"
expect -re "Repeat new passphrase for.*"
sleep 1
send -- "$password\r"
}
proc prompt_packet_password {password pinentry} {
verify_password $password
expect -re "Escrow packet passphrase.*"
sleep 1
send -- "$password\r"
if {$pinentry} {
expect -re ".*Passphrase.*"
sleep 1
send -- "$password\r"
}
}
proc prompt_new_packet_password {password pinentry} {
verify_password $password
expect -re "New packet passphrase.*"
sleep 1
send -- "$password\r"
expect -re "Repeat new packet passphrase.*"
sleep 1
send -- "$password\r"
if {$pinentry} {
expect -re ".*Passphrase.*"
sleep 1
send -- "$password\r"
expect -re ".*Passphrase.*"
sleep 1
send -- "$password\r"
}
}
eval spawn volume_key $::argv
if {"--reencrypt" in $::argv} {
if {"-d" in $::argv} {
prompt_cert_password $certpass
} else {
prompt_packet_password $packetpass $pinentry
}
prompt_new_packet_password $newpacketpass $pinentry
expect eof
} elseif {"--restore" in $::argv} {
if {"-d" in $::argv} {
prompt_cert_password $certpass
} else {
prompt_packet_password $packetpass $pinentry
}
prompt_new_luks_password $lukspass
expect eof
} elseif {"--save" in $::argv} {
prompt_luks_password $lukspass
if {"-c" ni $::argv} {
prompt_new_packet_password $packetpass $pinentry
}
expect eof
} elseif {[oneof {"--dump" "--secrets" "--setup-volume"} $::argv]} {
if {"-d" in $::argv} {
prompt_cert_password $certpass
} else {
prompt_packet_password $packetpass $pinentry
}
expect eof
}

View File

@ -1,146 +0,0 @@
diff --git a/lib/crypto.c b/lib/crypto.c
index 4b9006a..5b562d1 100644
--- a/lib/crypto.c
+++ b/lib/crypto.c
@@ -69,6 +69,115 @@ error_from_pr (GError **error)
g_free (err);
}
+/*
+ * FIPS compliant implementation of PK11_ImportSymKey().
+ * Source: https://github.com/ceph/ceph/pull/27104/files
+ */
+static PK11SymKey *
+import_sym_key (PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin,
+ CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx)
+{
+ CK_MECHANISM_TYPE wrap_mechanism = 0UL;
+ PK11SymKey *wrapping_key = NULL, *sym_key = NULL;
+ SECItem tmp_sec_item, wrapped_key_item, *raw_key_aligned = NULL;
+ PK11Context *wrap_key_crypt_context = NULL;
+ int block_size = 0;
+ size_t wrapped_key_size = 0;
+ unsigned char *wrapped_key = NULL;
+ int out_len = 0;
+ SECStatus ret = 0;
+
+ /* Fall back to PK11_ImportSymKey() if FIPS mode is disabled. */
+ if (PK11_IsFIPS () == PR_FALSE)
+ return PK11_ImportSymKey (slot, type, origin, operation, key, wincx);
+
+ /* Get the best mechanism for the wrapping operation. */
+ wrap_mechanism = PK11_GetBestWrapMechanism (slot);
+
+ /* Based on that mechanism, generate a symetric key <wrapping_key>. */
+ wrapping_key = PK11_KeyGen (slot, wrap_mechanism, NULL,
+ PK11_GetBestKeyLength (slot, wrap_mechanism),
+ NULL);
+ if (wrapping_key == NULL)
+ return NULL;
+
+ /* Create the context for the wrapping operation. The context contains:
+ * - <wrapping_key>
+ * - operation to perform (CKA_ENCRYPT)
+ */
+ memset (&tmp_sec_item, 0, sizeof (tmp_sec_item));
+ wrap_key_crypt_context = PK11_CreateContextBySymKey (wrap_mechanism,
+ CKA_ENCRYPT,
+ wrapping_key,
+ &tmp_sec_item);
+ if (wrap_key_crypt_context == NULL) {
+ PK11_FreeSymKey (wrapping_key);
+ return NULL;
+ }
+
+ /* Align <key> to the block size specified by the wrapping mechanism. */
+ block_size = PK11_GetBlockSize (wrap_mechanism, NULL);
+ raw_key_aligned = PK11_BlockData (key, block_size);
+ if (raw_key_aligned == NULL) {
+ PK11_DestroyContext (wrap_key_crypt_context, PR_TRUE);
+ PK11_FreeSymKey (wrapping_key);
+ return NULL;
+ }
+
+ /* Prepare for <key> wrap. First, allocate enough space for
+ * the wrapped <key>. Add the padding of the size of one block behind the
+ * aligned <key> to make sure the wrapping operation will not hit the wall.
+ */
+ wrapped_key_size = raw_key_aligned->len + block_size;
+ wrapped_key = g_try_malloc0 (wrapped_key_size);
+ if (wrapped_key == NULL) {
+ SECITEM_FreeItem (raw_key_aligned, PR_TRUE);
+ PK11_DestroyContext (wrap_key_crypt_context, PR_TRUE);
+ PK11_FreeSymKey (wrapping_key);
+ return NULL;
+ }
+
+ /* Do the wrap operation. <wrapped_key> is now a pair (<wrapping_key>, <key>)
+ * expressing that raw key <key> is now encrypted with the <wrapping_key>.
+ */
+ ret = PK11_CipherOp (wrap_key_crypt_context, wrapped_key, &out_len,
+ wrapped_key_size, raw_key_aligned->data,
+ raw_key_aligned->len);
+ if (ret != SECSuccess) {
+ g_free (wrapped_key);
+ SECITEM_FreeItem (raw_key_aligned, PR_TRUE);
+ PK11_DestroyContext (wrap_key_crypt_context, PR_TRUE);
+ PK11_FreeSymKey (wrapping_key);
+ return NULL;
+ }
+
+ /* Finish the wrapping operation and release no more needed resources. */
+ ret = PK11_Finalize (wrap_key_crypt_context);
+ SECITEM_FreeItem (raw_key_aligned, PR_TRUE);
+ PK11_DestroyContext (wrap_key_crypt_context, PR_TRUE);
+ if (ret != SECSuccess) {
+ g_free (wrapped_key);
+ PK11_FreeSymKey (wrapping_key);
+ return NULL;
+ }
+
+ /* Prepare for unwrapping the <key>. */
+ memset (&tmp_sec_item, 0, sizeof (tmp_sec_item));
+ memset (&wrapped_key_item, 0, sizeof (wrapped_key_item));
+ wrapped_key_item.data = wrapped_key;
+ wrapped_key_item.len = wrapped_key_size;
+
+ /* Unwrap the <key>. First, decrypt the <key> with the <wrapping_key> to get
+ * its raw form. Then make a symmetric key (<key>, <type>, <operation>). This
+ * makes a symmetric key from the raw <key> in a FIPS compliant manner.
+ */
+ sym_key = PK11_UnwrapSymKey (wrapping_key, wrap_mechanism, &tmp_sec_item,
+ &wrapped_key_item, type, operation, key->len);
+ g_free (wrapped_key);
+ PK11_FreeSymKey (wrapping_key);
+ return sym_key;
+}
+
/* LIBVK_PACKET_FORMAT_ASYMMETRIC */
/* Encrypt DATA of SIZE for CERT.
@@ -291,9 +400,9 @@ wrap_asymmetric (void **wrapped_secret, size_t *wrapped_secret_size,
CKM_GENERIC_SECRET_KEY_GEN. */
clear_secret_item.data = (void *)clear_secret_data;
clear_secret_item.len = clear_secret_size;
- secret_key = PK11_ImportSymKey (slot, CKM_GENERIC_SECRET_KEY_GEN,
- PK11_OriginUnwrap, CKA_WRAP,
- &clear_secret_item, pwfn_arg);
+ secret_key = import_sym_key (slot, CKM_GENERIC_SECRET_KEY_GEN,
+ PK11_OriginUnwrap, CKA_WRAP,
+ &clear_secret_item, pwfn_arg);
PK11_FreeSlot (slot);
if (secret_key == NULL)
{
@@ -471,9 +580,9 @@ wrap_symmetric (void **wrapped_secret, size_t *wrapped_secret_size, void **iv,
/* The disk encryption mechanism might not have a PKCS11 name, and we don't
really need to tell NSS specifics anyway, so just use
CKM_GENERIC_SECRET_KEY_GEN. */
- secret_key = PK11_ImportSymKey (slot, CKM_GENERIC_SECRET_KEY_GEN,
- PK11_OriginUnwrap, CKA_WRAP,
- &clear_secret_item, pwfn_arg);
+ secret_key = import_sym_key (slot, CKM_GENERIC_SECRET_KEY_GEN,
+ PK11_OriginUnwrap, CKA_WRAP,
+ &clear_secret_item, pwfn_arg);
PK11_FreeSlot (slot);
if (secret_key == NULL)
{

View File

@ -1,49 +0,0 @@
diff --git a/src/volume_key.c b/src/volume_key.c
index 24b70d6..9642072 100644
--- a/src/volume_key.c
+++ b/src/volume_key.c
@@ -17,6 +17,7 @@ Author: Miloslav Trmač <mitr@redhat.com> */
#include <config.h>
#include <assert.h>
+#include <errno.h>
#include <langinfo.h>
#include <locale.h>
#include <regex.h>
@@ -403,6 +404,7 @@ get_password (const char *prompt)
char buf[LINE_MAX], *p;
struct termios otermios;
gboolean echo_disabled;
+ int saved_errno = 0;
tty = fopen ("/dev/tty", "r+");
if (tty != NULL)
@@ -430,7 +432,8 @@ get_password (const char *prompt)
echo_disabled = tcsetattr (fileno (in_file), TCSAFLUSH, &ntermios) == 0;
}
- p = fgets(buf, sizeof(buf), in_file);
+ p = fgets (buf, sizeof (buf), in_file);
+ saved_errno = errno;
if (echo_disabled)
{
@@ -441,13 +444,15 @@ get_password (const char *prompt)
if (tty != NULL)
fclose (tty);
- if (p == NULL)
+ if (p == NULL) {
+ fprintf (stderr, "fgets: %s\n", strerror (saved_errno));
return NULL;
+ }
- p = strchr(buf, '\r');
+ p = strchr (buf, '\r');
if (p != NULL)
*p = '\0';
- p = strchr(buf, '\n');
+ p = strchr (buf, '\n');
if (p != NULL)
*p = '\0';

View File

@ -0,0 +1,59 @@
diff --git a/lib/kmip.c b/lib/kmip.c
index dda819a..333603c 100644
--- a/lib/kmip.c
+++ b/lib/kmip.c
@@ -1152,6 +1152,7 @@ kmip_decode_key_value (struct kmip_decoding_state *kmip,
break;
default:
+ kmip_key_value_free (res);
g_return_val_if_reached (-1);
}
res->attributes = g_ptr_array_new ();
@@ -1348,6 +1349,7 @@ kmip_decode_object_symmetric_key (struct kmip_decoding_state *kmip,
g_snprintf (num, sizeof (num), "%" G_GUINT32_FORMAT, res->block->type);
g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_KMIP_UNSUPPORTED_VALUE,
_("Unsupported symmetric key format %s"), num);
+ kmip_object_symmetric_key_free (res);
return -1;
}
*obj = res;
@@ -1384,6 +1386,7 @@ kmip_decode_object_secret_data (struct kmip_decoding_state *kmip,
g_snprintf (num, sizeof (num), "%" G_GUINT32_FORMAT, res->block->type);
g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_KMIP_UNSUPPORTED_VALUE,
_("Unsupported symmetric key format %s"), num);
+ kmip_object_secret_data_free (res);
return -1;
}
*obj = res;
diff --git a/lib/volume_luks.c b/lib/volume_luks.c
index d1c5d47..4d32d9b 100644
--- a/lib/volume_luks.c
+++ b/lib/volume_luks.c
@@ -547,8 +547,8 @@ luks_apply_secret (struct libvk_volume *vol, const struct libvk_volume *packet,
}
g_free (last_log_entry);
- g_return_val_if_fail (vol->v.luks->key_bytes == packet->v.luks->key_bytes,
- -1);
+ if (vol->v.luks->key_bytes != packet->v.luks->key_bytes)
+ goto err_passphrase;
luks_replace_key (vol, packet->v.luks->key);
luks_replace_passphrase (vol, passphrase);
vol->v.luks->passphrase_slot = res;
diff --git a/src/volume_key.c b/src/volume_key.c
index 074b187..24b70d6 100644
--- a/src/volume_key.c
+++ b/src/volume_key.c
@@ -735,6 +735,11 @@ write_packet (struct packet_output_state *pos, const char *filename,
|| g_file_set_contents (filename, packet, size, error) == FALSE)
{
g_prefix_error (error, _("Error creating `%s': "), filename);
+ if (packet != NULL) {
+ if (output_format_cleartext != 0)
+ memset (packet, 0, size);
+ g_free (packet);
+ }
return -1;
}
if (output_format_cleartext != 0)

View File

@ -1,12 +1,3 @@
From d0aa966c014d8301371e693966dcac3d9e9c0ccd Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Mon, 10 Sep 2018 13:07:41 +0200
Subject: [PATCH] Add suppport for opening LUKS2 devices
---
lib/volume_luks.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/volume_luks.c b/lib/volume_luks.c
index f4bf2c8..d1c5d47 100644
--- a/lib/volume_luks.c
@ -31,6 +22,3 @@ index f4bf2c8..d1c5d47 100644
if (r < 0)
goto err_cd;
return cd;
--
2.17.1

View File

@ -1,101 +1,140 @@
# Define `python3_sitearch' if there is no one:
%{!?python3_sitearch:%global python3_sitearch %(%{__python3} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")}
# Enable Python 3 in Fedora and RHEL > 7 as default:
%if 0%{?fedora} || 0%{?rhel} > 7
# Add `--without python3' option (enable python3 by default):
%bcond_without python3
%else
# Add `--with python3' option (disable python3 by default):
%bcond_with python3
%endif
# Drop Python 2 in Fedora >= 30 and RHEL > 7 as default:
%if 0%{?fedora} >= 30 || 0%{?rhel} > 7
%global drop_python2 1
%global configure_with_python2 no
%else
# Define `python2_sitearch' if there is no one:
%{!?python2_sitearch:%global python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
%global configure_with_python2 yes
%endif
%if %{with python3}
%global configure_with_python3 yes
%else
%global configure_with_python3 no
%endif
# Additional configure options:
%global with_pythons --with-python=%{configure_with_python2} --with-python3=%{?configure_with_python3}
Summary: An utility for manipulating storage encryption keys and passphrases
Name: volume_key
Version: 0.3.11
Release: 6%{?dist}
# lib/{SECerrs,SSLerrs}.h are both licensed under MPLv1.1, GPLv2 and LGPLv2
License: GPLv2 and (MPLv1.1 or GPLv2 or LGPLv2)
Group: Applications/System
URL: https://pagure.io/volume_key/
Requires: volume_key-libs%{?_isa} = %{version}-%{release}
Version: 0.3.12
Release: 23%{?dist}
License: GPL-2.0-only AND (MPL-1.1 OR GPL-2.0-or-later OR LGPL-2.1-or-later)
URL: https://pagure.io/%{name}/
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
Source0: https://releases.pagure.org/volume_key/volume_key-%{version}.tar.xz
# Add support for opening all types of LUKS devices (not just LUKS1)
# Resolves: rhbz#1626974
Patch0: volume_key-0.3.11-support_LUKS_all.patch
# Make volume_key working in FIPS mode
# Resolves: rhbz#2143223
Patch1: volume_key-0.3.11-FIPS.patch
# Diagnose patch to get more insight on whats wrong
Patch2: volume_key-0.3.11-show_get_password_error.patch
BuildRequires: cryptsetup-luks-devel, gettext-devel, glib2-devel, /usr/bin/gpg2
BuildRequires: gpgme-devel, libblkid-devel, nss-devel, python3-devel
Source0: https://releases.pagure.org/%{name}/%{name}-%{version}.tar.xz
# Support all LUKS devices
# - backport of 26c09768662d8958debe8c9410dae9fda02292c3
Patch0: volume_key-0.3.12-support_LUKS2_and_more.patch
# Fix resource leaks
# - backport of bf6618ec0b09b4e51fc97fa021e687fbd87599ba
Patch1: volume_key-0.3.12-fix_resource_leaks.patch
BuildRequires: autoconf, automake, libtool
BuildRequires: make
BuildRequires: gcc
BuildRequires: cryptsetup-devel, gettext-devel, glib2-devel, /usr/bin/gpg2
BuildRequires: gpgme-devel, libblkid-devel, nss-devel
BuildRequires: python3-devel, python3-setuptools
%if 0%{?drop_python2} < 1
BuildRequires: python2-devel
%endif
# Needed by %%check:
BuildRequires: nss-tools
%description
This package provides a command-line tool for manipulating storage volume
encryption keys and storing them separately from volumes.
The main goal of the software is to allow restoring access to an encrypted
hard drive if the primary user forgets the passphrase. The encryption key
back up can also be useful for extracting data after a hardware or software
failure that corrupts the header of the encrypted volume, or to access the
%global desc_common The main goal of the software is to allow restoring access to an encrypted\
hard drive if the primary user forgets the passphrase. The encryption key\
back up can also be useful for extracting data after a hardware or software\
failure that corrupts the header of the encrypted volume, or to access the\
company data after an employee leaves abruptly.
%global desc_app This package provides a command-line tool for manipulating storage volume\
encryption keys and storing them separately from volumes.\
\
%{desc_common}
%global desc_lib This package provides lib%{name}, a library for manipulating storage volume\
encryption keys and storing them separately from volumes.\
\
%{desc_common}
%global desc_python(V:) This package provides %%{-V:Python %%{-V*}}%%{!-V:Python} bindings for lib%{name}, a library for\
manipulating storage volume encryption keys and storing them separately from\
volumes.\
\
%{desc_common}\
\
%{name} currently supports only the LUKS volume encryption format. Support\
for other formats is possible, some formats are planned for future releases.
%description
%{desc_app}
%package devel
Summary: A library for manipulating storage encryption keys and passphrases
Group: Development/Libraries
Requires: volume_key-libs%{?_isa} = %{version}-%{release}
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
%description devel
This package provides libvolume_key, a library for manipulating storage volume
encryption keys and storing them separately from volumes.
The main goal of the software is to allow restoring access to an encrypted
hard drive if the primary user forgets the passphrase. The encryption key
back up can also be useful for extracting data after a hardware or software
failure that corrupts the header of the encrypted volume, or to access the
company data after an employee leaves abruptly.
%{desc_lib}
%package libs
Summary: A library for manipulating storage encryption keys and passphrases
Group: System Environment/Libraries
Requires: /usr/bin/gpg2
%description libs
This package provides libvolume_key, a library for manipulating storage volume
encryption keys and storing them separately from volumes.
%{desc_lib}
The main goal of the software is to allow restoring access to an encrypted
hard drive if the primary user forgets the passphrase. The encryption key
back up can also be useful for extracting data after a hardware or software
failure that corrupts the header of the encrypted volume, or to access the
company data after an employee leaves abruptly.
%if 0%{?drop_python2} < 1
%package -n python2-%{name}
%{?python_provide:%python_provide python2-%{name}}
Summary: Python bindings for lib%{name}
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
%package -n python3-volume_key
%{?python_provide:%python_provide python3-volume_key}
Summary: Python bindings for libvolume_key
Group: System Environment/Libraries
Requires: volume_key-libs%{?_isa} = %{version}-%{release}
%description -n python2-%{name}
%desc_python
%endif
%description -n python3-volume_key
This package provides Python bindings for libvolume_key, a library for
manipulating storage volume encryption keys and storing them separately from
volumes.
%if %{with python3}
%package -n python3-%{name}
%{?python_provide:%python_provide python3-%{name}}
Summary: Python 3 bindings for lib%{name}
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
The main goal of the software is to allow restoring access to an encrypted
hard drive if the primary user forgets the passphrase. The encryption key
back up can also be useful for extracting data after a hardware or software
failure that corrupts the header of the encrypted volume, or to access the
company data after an employee leaves abruptly.
volume_key currently supports only the LUKS volume encryption format. Support
for other formats is possible, some formats are planned for future releases.
%description -n python3-%{name}
%desc_python -V 3
%endif
%prep
%setup -q
%patch0 -p1
%patch1 -p1
%patch2 -p1
autoreconf -fiv
%build
%configure
make %{?_smp_mflags}
%configure %{?with_pythons}
%make_build
%install
make install DESTDIR=$RPM_BUILD_ROOT INSTALL='install -p'
%make_install
%find_lang volume_key
# Remove libtool archive
find %{buildroot} -type f -name "*.la" -delete
%find_lang %{name}
%check
make check || { \
@ -105,64 +144,119 @@ echo "=================================================================="; \
exit 1; \
}
%clean
rm -rf $RPM_BUILD_ROOT
%ldconfig_scriptlets libs
%files
%defattr(-,root,root,-)
%doc README contrib
%{_bindir}/volume_key
%{_mandir}/man8/volume_key.8*
%{_bindir}/%{name}
%{_mandir}/man8/%{name}.8*
%files devel
%defattr(-,root,root,-)
%{_includedir}/volume_key
%exclude %{_libdir}/libvolume_key.la
%{_libdir}/libvolume_key.so
%{_includedir}/%{name}
%{_libdir}/lib%{name}.so
%files libs -f volume_key.lang
%defattr(-,root,root,-)
%files libs -f %{name}.lang
%doc AUTHORS COPYING ChangeLog NEWS
%{_libdir}/libvolume_key.so.*
%{_libdir}/lib%{name}.so.*
%files -n python3-volume_key
%defattr(-,root,root,-)
%exclude %{python3_sitearch}/_volume_key.la
%{python3_sitearch}/_volume_key.so
%{python3_sitearch}/volume_key.py*
%{python3_sitearch}/__pycache__/volume_key.*
%if 0%{?drop_python2} < 1
%files -n python2-%{name}
%{python2_sitearch}/_%{name}.so
%{python2_sitearch}/%{name}.py*
%endif
%if %{with python3}
%files -n python3-%{name}
%{python3_sitearch}/_%{name}.so
%{python3_sitearch}/%{name}.py*
%{python3_sitearch}/__pycache__/%{name}.*
%endif
%changelog
* Fri Jul 21 2023 Jiri Kucera <jkucera@redhat.com> - 0.3.11-6
- Make volume_key working in FIPS mode
Resolves: #2143223
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 0.3.12-23
- Bump release for October 2024 mass rebuild:
Resolves: RHEL-64018
* Wed Aug 14 2019 Jiri Kucera <jkucera@redhat.com> - 0.3.11-5
- Place %%find_lang to proper place
Resolves: #1665135
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 0.3.12-22
- Bump release for June 2024 mass rebuild
* Tue Jan 08 2019 Jiri Kucera <jkucera@redhat.com> - 0.3.11-4
- fixed License
- Requires: /usr/bin/gpg2 in libs subpackage
- Added support for opening all types of LUKS devices
Resolves: #1626974
* Sat Jan 27 2024 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-21
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Thu Aug 09 2018 Jiri Kucera <jkucera@redhat.com> - 0.3.11-3
- Added %%check
Resolves: #1614420
* Sat Jul 22 2023 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-20
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Tue Jul 24 2018 Jiri Kucera <jkucera@redhat.com> - 0.3.11-2
- added missing licenses
- update to gpg2
* Tue Jun 13 2023 Python Maint <python-maint@redhat.com> - 0.3.12-19
- Rebuilt for Python 3.12
* Thu Jul 19 2018 Charalampos Stratakis <cstratak@redhat.com> - 0.3.11-1
- Update to 3.11
- Change to Python 3
* Sat Jan 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-18
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Fri Jul 13 2018 Petr Viktorin <pviktori@redhat.com> - 0.3.9-20
- Allow Python 2 for build
* Sat Jul 23 2022 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-17
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Mon Jun 13 2022 Python Maint <python-maint@redhat.com> - 0.3.12-16
- Rebuilt for Python 3.11
* Sat Jan 22 2022 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-15
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
* Wed Aug 04 2021 Jiri Kucera <jkucera@redhat.com> - 0.3.12-14
- Fix FTBFS
- Move License tag back to GPLv2 (this is the effective license)
- Use make macros
* Fri Jul 23 2021 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-13
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Fri Jun 04 2021 Python Maint <python-maint@redhat.com> - 0.3.12-12
- Rebuilt for Python 3.10
* Wed Mar 31 2021 Jiri Kucera <jkucera@redhat.com> - 0.3.12-11
- Fix resource leaks
* Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-10
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-9
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Tue May 26 2020 Miro Hrončok <mhroncok@redhat.com> - 0.3.12-8
- Rebuilt for Python 3.9
* Fri Jan 31 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Thu Oct 03 2019 Miro Hrončok <mhroncok@redhat.com> - 0.3.12-6
- Rebuilt for Python 3.8.0rc1 (#1748018)
* Mon Aug 19 2019 Miro Hrončok <mhroncok@redhat.com> - 0.3.12-5
- Rebuilt for Python 3.8
* Sat Jul 27 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Sun Feb 03 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.12-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Wed Jan 23 2019 Jiri Kucera <jkucera@redhat.com> - 0.3.12-2
- Add support for LUKS2 and more
- Fix License tag
* Mon Oct 08 2018 Jiri Kucera <jkucera@redhat.com> - 0.3.12-1
- Update to volume_key-0.3.12
Resolves: #1634850
* Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.10-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Wed May 16 2018 Jiri Kucera <jkucera@redhat.com> - 0.3.10-1
- Update to volume_key-0.3.10
Resolves: #1479349, #1517016
* Wed Feb 14 2018 Iryna Shcherbina <ishcherb@redhat.com> - 0.3.9-20
- Update Python 2 dependency declarations to new packaging standards
(See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3)
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.3.9-19
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild