From b02e5fd98135ce8f6271e22a193085a14f66a7af Mon Sep 17 00:00:00 2001 From: Dave Heller Date: Sat, 18 Aug 2018 22:34:06 -0400 Subject: Support multiple KMS in Production mode This adds support for PKCS11 as an alternate key management system in place of signframework, and adds the configuation property SB_KMS and a new command line option --kms to select between them. If unset the default is "signframework". If set to "pkcs11" two additional configuration properties, specifying the token name and the shared library implementing the token, are recognized. These properties are set by environment, or via the INI under a new section [pkcs11]. --- crtSignedContainer.sh | 179 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 136 insertions(+), 43 deletions(-) diff --git a/crtSignedContainer.sh b/crtSignedContainer.sh index d84100f..d231b5f 100755 --- a/crtSignedContainer.sh +++ b/crtSignedContainer.sh @@ -7,6 +7,7 @@ P=${0##*/} SIGN_MODE=local +KMS=signframework HW_KEY_ARGS="" SW_KEY_ARGS="" @@ -39,6 +40,8 @@ usage () { echo " -o, --code-start-offset code start offset for software header in hex" echo " -f, --flags prefix header flags in hex" echo " -m, --mode signing mode: local, independent or production" + echo " -k, --kms key management system for retrieving keys and signatures" + echo " (choices are \"signframework\" or \"pkcs11\")" echo " -s, --scratchDir scratch directory to use for file caching, etc." echo " -L, --label name or identifier of the module being built (8 char max)" echo " --contrHdrOut file write container header only (w/o payload)" @@ -252,9 +255,19 @@ parseIni () { findArtifact () { local f local found + local scope for f in "$@" do + # If filename starts with ./ search only this component cache. + if [ "${f:0:2}" == "./" ] + then + f="${f:2}" + scope=local + else + scope=global + fi + # Look for artifact in the local cache found=$(find "$T" -name "$f" | head -1) if [ "$found" ]; then @@ -262,7 +275,9 @@ findArtifact () { return fi - # If not found, look elsewhere in the cache + test "$scope" == "local" && continue + + # Look elsewhere in the cache found=$(find "$TOPDIR" -name "$f" | head -1) if [ "$found" ]; then cp -p "$found" "$T/" @@ -300,6 +315,7 @@ for arg in "$@"; do "--code-start-offset") set -- "$@" "-o" ;; "--protectedPayload") set -- "$@" "-l" ;; "--out") set -- "$@" "-i" ;; + "--kms") set -- "$@" "-k" ;; "--mode") set -- "$@" "-m" ;; "--scratchDir") set -- "$@" "-s" ;; "--label") set -- "$@" "-L" ;; @@ -315,7 +331,7 @@ for arg in "$@"; do done # Process command-line arguments -while getopts -- ?hdvw:a:b:c:p:q:r:f:o:l:i:m:s:L:4:5:6:7:89: opt +while getopts -- ?hdvw:a:b:c:p:q:r:f:o:l:i:m:k:s:L:4:5:6:7:89: opt do case "${opt:?}" in v) SB_VERBOSE="TRUE";; @@ -331,6 +347,7 @@ do o) CS_OFFSET="$OPTARG";; l) PAYLOAD="$OPTARG";; i) OUTPUT="$OPTARG";; + k) KMS="$(to_lower "$OPTARG")";; m) SIGN_MODE="$(to_lower "$OPTARG")";; s) SB_SCRATCH_DIR="$OPTARG";; L) LABEL="$OPTARG";; @@ -352,10 +369,11 @@ do done # These are the only env vars that override a command line option +test "$SB_KMS" && KMS="$(to_lower "$SB_KMS")" test "$SB_SIGN_MODE" && SIGN_MODE="$(to_lower "$SB_SIGN_MODE")" test "$SB_PROJECT_INI" && PROJECT_INI="$SB_PROJECT_INI" -# What op-buid calls development mode, we call local mode +# What op-build calls development mode, we call local mode test "$SIGN_MODE" == development && SIGN_MODE=local echo "--> $P: Signing mode: $SIGN_MODE" @@ -365,7 +383,7 @@ echo "--> $P: Signing mode: $SIGN_MODE" # if [ "$(to_upper "$LABEL")" == SBKTRAND ] then - # Key transistion container may have its own ini file + # Key transition container may have its own ini file test "$SB_PROJECT_INI_TRANS" && PROJECT_INI=$SB_PROJECT_INI_TRANS fi @@ -384,6 +402,8 @@ then signproject_hw_signing_project_basename="" signproject_fw_signing_project_basename="" signproject_getpubkey_project_basename="" + pkcs11_module="" + pkcs11_token="" echo "--> $P: Parsing INI file: $PROJECT_INI" parseIni "$PROJECT_INI" @@ -405,6 +425,9 @@ then SF_FW_SIGNING_PROJECT_BASE="$signproject_fw_signing_project_basename" test "$signproject_getpubkey_project_basename" && \ SF_GETPUBKEY_PROJECT_BASE="$signproject_getpubkey_project_basename" + + test "$pkcs11_module" && SB_PKCS11_MODULE="$pkcs11_module" + test "$pkcs11_token" && SB_PKCS11_TOKEN="$pkcs11_token" fi # @@ -541,6 +564,12 @@ then : "${SF_GETPUBKEY_PROJECT_BASE:=getpubkeyecc}" fi +# +# Set defaults for PKCS11 +# +: "${SB_PKCS11_MODULE:=/usr/lib64/pkcs11/libsofthsm2.so}" +: "${SB_PKCS11_TOKEN:=P9Signing}" + # # Get the public keys # @@ -654,16 +683,33 @@ then echo "--> $P: Found key for HW key $(to_upper $KEY).${msg}" else # No key found, request one. - KEYFILE="$KEYFILE_BASE.raw" echo "--> $P: Requesting public key for HW key $(to_upper $KEY)..." - sf_client $SF_DEBUG_ARGS -project "$SF_GETPUBKEY_PROJECT_BASE" \ - -param "-signproject $SF_PROJECT" \ - -epwd "$SF_EPWD" -comments "Requesting $SF_PROJECT" \ - -url sftp://$SF_USER@$SF_SERVER -pkey "$SF_SSHKEY" \ - -o "$T/$KEYFILE" - rc=$? - test $rc -ne 0 && die "Call to sf_client failed with error: $rc" + if [ "$KMS" == "signframework" ] + then + # Output is pubkey in raw format + KEYFILE="$KEYFILE_BASE.raw" + sf_client $SF_DEBUG_ARGS -project "$SF_GETPUBKEY_PROJECT_BASE" \ + -param "-signproject $SF_PROJECT" \ + -epwd "$SF_EPWD" -comments "Requesting $SF_PROJECT" \ + -url sftp://$SF_USER@$SF_SERVER -pkey "$SF_SSHKEY" \ + -o "$T/$KEYFILE" + + elif [ "$KMS" == "pkcs11" ] + then + # Output is pubkey in PEM format + KEYFILE="$KEYFILE_BASE.pub" + pkcs11-tool --module $SB_PKCS11_MODULE \ + --token-label $SB_PKCS11_TOKEN \ + --read-object --type pubkey --label $SF_PROJECT | \ + openssl ec -inform der -pubout -pubin > "$T/$KEYFILE" + + else + die "Unsupported KMS: $KMS" + fi + + rc=$? + test $rc -ne 0 && die "Call to KMS client failed with error: $rc" test "$(find "$T" -name $KEYFILE)" || \ die "Unable to retrieve HW key $(to_upper $KEY)." @@ -693,16 +739,28 @@ then echo "--> $P: Found key for SW key $(to_upper $KEY).${msg}" else # No key found, request one. - KEYFILE="$KEYFILE_BASE.raw" echo "--> $P: Requesting public key for SW key $(to_upper $KEY)..." - sf_client $SF_DEBUG_ARGS -project "$SF_GETPUBKEY_PROJECT_BASE" \ - -param "-signproject $SF_PROJECT" \ - -epwd "$SF_EPWD" -comments "Requesting $SF_PROJECT" \ - -url sftp://$SF_USER@$SF_SERVER -pkey "$SF_SSHKEY" \ - -o "$T/$KEYFILE" - rc=$? - test $rc -ne 0 && die "Call to sf_client failed with error: $rc" + if [ "$KMS" == "signframework" ] + then + KEYFILE="$KEYFILE_BASE.raw" + sf_client $SF_DEBUG_ARGS -project "$SF_GETPUBKEY_PROJECT_BASE" \ + -param "-signproject $SF_PROJECT" \ + -epwd "$SF_EPWD" -comments "Requesting $SF_PROJECT" \ + -url sftp://$SF_USER@$SF_SERVER -pkey "$SF_SSHKEY" \ + -o "$T/$KEYFILE" + + elif [ "$KMS" == "pkcs11" ] + then + KEYFILE="$KEYFILE_BASE.pub" + pkcs11-tool --module $SB_PKCS11_MODULE \ + --token-label $SB_PKCS11_TOKEN \ + --read-object --type pubkey --label $SF_PROJECT | \ + openssl ec -inform der -pubout -pubin > "$T/$KEYFILE" + fi + + rc=$? + test $rc -ne 0 && die "Call to KMS client failed with error: $rc" test "$(find "$T" -name $KEYFILE)" || \ die "Unable to retrieve SW key $(to_upper $KEY)." @@ -869,17 +927,29 @@ then echo "--> $P: Found sig for HW key $(to_upper $KEY).${msg}" else # No signature found, request one. - test "$KEYFILE" == __getkey && break - - SIGFILE="$SIGFILE_BASE.raw" + test "$KEYFILE" == __getkey && break # (unless instructed not to) echo "--> $P: Requesting signature for HW key $(to_upper $KEY)..." - sf_client $SF_DEBUG_ARGS -project $SF_PROJECT -epwd "$SF_EPWD" \ - -comments "Requesting sig for $SF_PROJECT" \ - -url sftp://$SF_USER@$SF_SERVER -pkey "$SF_SSHKEY" \ - -payload "$T/prefix_hdr" -o "$T/$SIGFILE" - rc=$? - test $rc -ne 0 && die "Call to sf_client failed with error: $rc" + if [ "$KMS" == "signframework" ] + then + # Output is signature in raw format + SIGFILE="$SIGFILE_BASE.raw" + sf_client $SF_DEBUG_ARGS -project $SF_PROJECT -epwd "$SF_EPWD" \ + -comments "Requesting sig for $SF_PROJECT" \ + -url sftp://$SF_USER@$SF_SERVER -pkey "$SF_SSHKEY" \ + -payload "$T/prefix_hdr" -o "$T/$SIGFILE" + + elif [ "$KMS" == "pkcs11" ] + then + # Output is signature in DER format + SIGFILE="$SIGFILE_BASE.sig" + /bin/openssl dgst -engine pkcs11 -keyform engine \ + -sign "pkcs11:token=$SB_PKCS11_TOKEN;object=$SF_PROJECT" \ + -sha512 -out "$T/$SIGFILE" "$T/prefix_hdr" + fi + + rc=$? + test $rc -ne 0 && die "Call to KMS client failed with error: $rc" test "$(find "$T" -name $SIGFILE)" || \ die "Unable to retrieve sig for HW key $(to_upper $KEY)." @@ -892,33 +962,56 @@ then done for KEY in p q r; do - SF_PROJECT=${SF_FW_SIGNING_PROJECT_BASE}_${KEY} - SIGFILE=project.$SF_PROJECT.SW_sig_$KEY.raw - varname=SW_KEY_$(to_upper $KEY); KEYFILE=${!varname} # Handle the special values, or empty value test -z "$KEYFILE" && break test "$KEYFILE" == __skip && break + SF_PROJECT=${SF_FW_SIGNING_PROJECT_BASE}_${KEY} + SIGFILE_BASE=project.$SF_PROJECT.SW_sig_$KEY + # Look for a signature in the local cache dir, if found use it. - if [ -f "$T/$SIGFILE" ] && \ - [ "$(to_upper "$LABEL")" != SBKT ] && \ - [ "$(to_upper "$LABEL")" != SBKTRAND ] + # (but never reuse a sig for SBKT, the payload is always regenerated) + if [ "$(to_upper "$LABEL")" == SBKT ] || \ + [ "$(to_upper "$LABEL")" == SBKTRAND ] then + SIGFILE="" + else + SIGFILE=$(findArtifact "./$SIGFILE_BASE.sig" "./$SIGFILE_BASE.raw") + fi + + if [ "$SIGFILE" ]; then test "$SB_VERBOSE" && msg=" ($SIGFILE)" - echo "--> $P: Found signature for SW key $(to_upper $KEY).${msg}" + echo "--> $P: Found sig for SW key $(to_upper $KEY).${msg}" else # No signature found, request one. - test "$KEYFILE" == __getkey && continue + test "$KEYFILE" == __getkey && break # (unless instructed not to) echo "--> $P: Requesting signature for SW key $(to_upper $KEY)..." - sf_client $SF_DEBUG_ARGS -project $SF_PROJECT -epwd "$SF_EPWD" \ - -comments "Requesting sig for $LABEL from $SF_PROJECT" \ - -url sftp://$SF_USER@$SF_SERVER -pkey "$SF_SSHKEY" \ - -payload "$T/software_hdr.md.bin" -o "$T/$SIGFILE" + + if [ "$KMS" == "signframework" ] + then + # Output is signature in raw format + SIGFILE="$SIGFILE_BASE.raw" + sf_client $SF_DEBUG_ARGS -project $SF_PROJECT -epwd "$SF_EPWD" \ + -comments "Requesting sig for $LABEL from $SF_PROJECT" \ + -url sftp://$SF_USER@$SF_SERVER -pkey "$SF_SSHKEY" \ + -payload "$T/software_hdr.md.bin" -o "$T/$SIGFILE" + + elif [ "$KMS" == "pkcs11" ] + then + # Output is signature in DER format + SIGFILE="$SIGFILE_BASE.sig" + /bin/openssl dgst -engine pkcs11 -keyform engine \ + -sign "pkcs11:token=$SB_PKCS11_TOKEN;object=$SF_PROJECT" \ + -sha512 -out "$T/$SIGFILE" "$T/software_hdr" + fi + rc=$? + test $rc -ne 0 && die "Call to KMS client failed with error: $rc" - test $rc -ne 0 && die "Call to sf_client failed with error: $rc" + test "$(find "$T" -name $SIGFILE)" || \ + die "Unable to retrieve sig for SW key $(to_upper $KEY)." echo "--> $P: Retrieved signature for SW key $(to_upper $KEY)." fi @@ -973,7 +1066,7 @@ fi if [ "$(to_upper "$LABEL")" == SBKTRAND ] then - # Key transistion container may have its own verify value + # Key transition container may have its own verify value test "$SB_VERIFY_TRANS" && SB_VERIFY=$SB_VERIFY_TRANS fi -- cgit v1.2.1