Skip to content

Hmac support #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ set(ZPC_HEADERS
include/zpc/aes_cmac.h
include/zpc/ecc_key.h
include/zpc/ecdsa_ctx.h
include/zpc/hmac_key.h
include/zpc/hmac.h
)

set(ZPC_SOURCES
Expand All @@ -64,6 +66,8 @@ set(ZPC_SOURCES
src/ecc_key.c
src/ecdsa_ctx.c
src/pvsecrets.c
src/hmac_key.c
src/hmac.c

src/zkey/utils.c
src/zkey/pkey.c
Expand Down Expand Up @@ -382,6 +386,8 @@ set(ZPC_TEST_SOURCES
test/b_aes_gcm.c
test/b_ecc_key.c
test/b_ecdsa_ctx.c
test/b_hmac_key.c
test/b_hmac.c
test/t_system.cc
test/t_testlib.cc
test/t_environment.cc
Expand All @@ -395,6 +401,8 @@ set(ZPC_TEST_SOURCES
test/t_aes_gcm.cc
test/t_ecc_key.cc
test/t_ecdsa_ctx.cc
test/t_hmac_key.cc
test/t_hmac.cc
)

add_executable(runtest ${ZPC_TEST_SOURCES})
Expand Down
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ Message authentication (MAC):

AES-128-CMAC, AES-192-CMAC, AES-256-CMAC

Hash-based message authentication (HMAC)

HMAC-SHA-224, HMAC-SHA-256, HMAC-SHA-384, HMAC-SHA-512

Authenticated Encryption (AEAD):

AES-128-CCM, AES-192-CCM, AES-256-CCM
Expand Down Expand Up @@ -58,6 +62,11 @@ Additional hardware and software prerequisites for ECDSA:
- CCA host library version 7.1 or later for CCA type keys
- EP11 host library version 3.0 or later for EP11 type keys

Additional hardware and software prerequisites for HMAC:
- Message security assist (MSA) 11 (IBM z17 or later)
- A KVM guest in IBM Secure Execution mode for PVSECRET type keys
- Kernel 6.13 or later with support for PVSECRET type keys

Building `libzpc`:

mkdir build && cd build
Expand Down Expand Up @@ -101,6 +110,23 @@ For ECDSA, the following environment variables can be passed to `./runtest`:
and key type.
- `ZPC_TEST_EC_KEY_APQNS=<apqns>` : Test the `<apqns>`.

For HMAC, the following environment variables can be passed to `./runtest`:
- `ZPC_TEST_HMAC_KEY_TYPE=<type>` : The only supported choice for `<type>` is `ZPC_HMAC_KEY_TYPE_PVSECRET`.
- `ZPC_TEST_HMAC_HASH_FUNCTION=<hfunc>` : The choices for `<hfunc>` are `SHA-224`, `SHA-256`, `SHA-384`, and `SHA-512`.
There are no MKVP or APQN related variables for HMAC.

For PVSECRET type keys, the following environment variable must be passed to `./runtest`:
- `ZPC_TEST_PVSECRET_LIST_FILE=<list-file>` : The `<list-file>` must be created with the pvsecret utility
as part of s390-tools v2.37 or later. Perform a 'pvsecret list' command and redirect the output to the list file.
Testers may optionally add clear key data, used when creating Ultravisor retrievable secrets, to the
list file. Example:

7 HMAC-SHA-256-KEY:
0xb620b6d76f89910aff90ff9 ... <- the secret ID
0xa783830e0bd6f3ae8cade16b3004 ... <- the clear key

If clear key data is available, additional tests (pvsecret_kat) are performed.

See

./runtest -h
Expand Down
30 changes: 27 additions & 3 deletions include/zpc/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,17 +482,41 @@ extern "C" {
# define ZPC_ERROR_PVSECRET_TYPE_NOT_SUPPORTED 79

/**
* \def ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV
* \brief the given pvsecret ID does not belong to a secret on this system.
* \def ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV_OR_INVALID_TYPE
* \brief the given pvsecret ID does either not exist or belongs to a different secret type.
*/
# define ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV 80
# define ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV_OR_INVALID_TYPE 80

/**
* \def ZPC_ERROR_IOCTLVERIFYKEY2
* \brief PKEY_VERIFYKEY2 ioctl failed.
*/
# define ZPC_ERROR_IOCTLVERIFYKEY2 81

/**
* \def ZPC_ERROR_HMAC_HASH_FUNCTION_NOTSET
* \brief HMAC hash function not set.
*/
# define ZPC_ERROR_HMAC_HASH_FUNCTION_NOTSET 82

/**
* \def ZPC_ERROR_HMAC_HASH_FUNCTION_INVALID
* \brief HMAC hash function invalid.
*/
# define ZPC_ERROR_HMAC_HASH_FUNCTION_INVALID 83

/**
* \def ZPC_ERROR_HMAC_KEYGEN_VIA_SYSFS_FAILED
* \brief HMAC key generation via sysfs attributes failed.
*/
# define ZPC_ERROR_HMAC_KEYGEN_VIA_SYSFS 84

/**
* \def ZPC_ERROR_CREATE_BLOCKSIZED_KEY
* \brief Creating a block-sized HMAC key failed.
*/
# define ZPC_ERROR_CREATE_BLOCKSIZED_KEY 85

/**
* \fn const char *zpc_error_string(int err)
* \brief Map an error code to the corresponding error string.
Expand Down
88 changes: 88 additions & 0 deletions include/zpc/hmac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright IBM Corp. 2025
*
* libzpc is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/

#ifndef ZPC_HMAC_H
# define ZPC_HMAC_H
# ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
# endif

/**
* \file zpc/hmac.h
*
* \brief HMAC API
*
* Message authentication API for the Hash-based Message Authentication
* Code (HMAC).
*/

# include <zpc/hmac_key.h>
# include <stddef.h>

struct zpc_hmac;

/**
* Allocate a new context for an HMAC operation.
* \param[in,out] ctx HMAC context
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_alloc(struct zpc_hmac **ctx);
/**
* Set the key to be used in the context of an HMAC operation.
* \param[in,out] ctx HMAC context
* \param[in] key HMAC key
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_set_key(struct zpc_hmac *ctx, struct zpc_hmac_key *key);
/**
* Do an HMAC signing operation.
* \param[in,out] ctx HMAC context
* \param[in,out] mac message authentication code when set to NULL, this
* indicates that an internal intermediate MAC is calculated and further
* intermediate calls with additional msg data may follow. If the mac parm is
* not NULL and the maclen is a valid MAC length (dependent on the underlying
* hash function of the key) the final MAC is computed.
* \param[in] maclen message authentication code length [bytes]
* \param[in] msg message
* \param[in] msglen message length [bytes]
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_sign(struct zpc_hmac *ctx, unsigned char *mac,
size_t maclen, const unsigned char *msg, size_t msglen);
/**
* Do an HMAC verify operation.
* \param[in,out] ctx HMAC context
* \param[in,out] mac message authentication code if the mac parm is NULL, then
* an intermediate verify op is performed. If the mac parm is not NULL and the
* maclen is a valid MAC length (dependent on the underlying hash function of
* the key), then the given MAC is checked for correctness.
* \param[in] maclen message authentication code length [bytes]
* \param[in] msg message
* \param[in] msglen message length [bytes]
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_verify(struct zpc_hmac *ctx, const unsigned char *mac,
size_t maclen, const unsigned char *msg, size_t msglen);
/**
* Free an HMAC context.
* \param[in,out] ctx HMAC context
*/
__attribute__((visibility("default")))
void zpc_hmac_free(struct zpc_hmac **ctx);

# ifdef __cplusplus
/* *INDENT-OFF* */
}
/* *INDENT-ON* */
# endif
#endif
126 changes: 126 additions & 0 deletions include/zpc/hmac_key.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright IBM Corp. 2025
*
* libzpc is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/

#ifndef ZPC_HMAC_KEY_H
# define ZPC_HMAC_KEY_H
# ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
# endif

/**
* \file zpc/hmac_key.h
* \brief HMAC key API.
*
* Manage
* \cite HMAC keys.
*/

# include <stddef.h>

/*
* These constants match with kernel's pkey.h, enum pkey_key_type.
*/
# define ZPC_HMAC_KEY_TYPE_PVSECRET 9

typedef enum {
ZPC_HMAC_SECRET_TYPE_NOT_SET = -2,
ZPC_HMAC_SECRET_TYPE_INVALID = -1,
ZPC_HMAC_SECRET_HMAC_SHA_256 = 0x09, /* architected key types, also below */
ZPC_HMAC_SECRET_HMAC_SHA_512 = 0x0a,
} zpc_hmacsecret_type_t;

typedef enum {
ZPC_HMAC_HASHFUNC_NOT_SET = -2,
ZPC_HMAC_HASHFUNC_INVALID = -1,
ZPC_HMAC_HASHFUNC_SHA_224 = 0,
ZPC_HMAC_HASHFUNC_SHA_256,
ZPC_HMAC_HASHFUNC_SHA_384,
ZPC_HMAC_HASHFUNC_SHA_512,
} zpc_hmac_hashfunc_t;

struct zpc_hmac_key;

/**
* Allocate a new HMAC key object with reference count 1.
* \param[in,out] key HMAC key
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_key_alloc(struct zpc_hmac_key **key);
/**
* Set the HMAC key type.
* \param[in,out] key HMAC key
* \param[in] type currently only one type ZPC_HMAC_KEY_TYPE_PVSECRET is
* supported.
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_key_set_type(struct zpc_hmac_key *key, int type);
/**
* Set the hash function to be used in the context of an HMAC operation.
* \param[in,out] ctx HMAC context
* \param[in] func HMAC hash function
* The size of the HMAC key (64 bytes or 128 bytes) is given by the block size
* of the hash function: for sha224 and sha256, the key size is set to 64 bytes,
* for sha384 and sha512, the key size is set to 128 bytes.
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_key_set_hash_function(struct zpc_hmac_key *key, zpc_hmac_hashfunc_t func);
/**
* Import an HMAC protected key origin (secure key or retrievable secret ID).
* \param[in,out] key HMAC key
* \param[in] seckey HMAC protected key origin
* \param[in] seckeylen HMAC key origin length [bytes]
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_key_import(struct zpc_hmac_key *key, const unsigned char *origin,
size_t originlen);
/**
* Import an HMAC clear-key.
* \param[in,out] key HMAC key
* \param[in] clearkey HMAC clear-key
* \param[in] keylen HMAC clear-key size [bytes]
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_key_import_clear(struct zpc_hmac_key *key,
const unsigned char *clrkey, size_t keylen);
/**
* Export an HMAC protected key origin (secure key or retrievable secret ID).
* \param[in,out] key HMAC key
* \param[out] seckey HMAC protected key origin
* \param[in,out] seckeylen origin length [bytes]
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_key_export(struct zpc_hmac_key *key, unsigned char *origin,
size_t *originlen);
/**
* Generate a random HMAC protected-key.
* \param[in,out] key HMAC key
* \return 0 on success. Otherwise, a non-zero error code is returned.
*/
__attribute__((visibility("default")))
int zpc_hmac_key_generate(struct zpc_hmac_key *key);
/**
* Decrease the reference count of an HMAC key object
* and free it the count reaches 0.
* \param[in,out] key HMAC key
*/
__attribute__((visibility("default")))
void zpc_hmac_key_free(struct zpc_hmac_key **key);

# ifdef __cplusplus
/* *INDENT-OFF* */
}
/* *INDENT-ON* */
# endif
#endif
18 changes: 18 additions & 0 deletions libzpc.map
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,22 @@ global:
local: *;
} ZPC_1.1.0;

ZPC_1.4.0 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we skip 1.3.0? If this related to other features, I would recommend to do the PRs in the right sequence.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.3.0 (and even 1.3.1) is already upstream. This was the fips 140-3 update in 2024 and caused the API behavior to change, but there were no new API functions. Therefore we go to 1.4.0 now.

global:
zpc_hmac_key_alloc;
zpc_hmac_key_set_type;
zpc_hmac_key_set_hash_function;
zpc_hmac_key_generate;
zpc_hmac_key_free;

zpc_hmac_alloc;
zpc_hmac_set_key;
zpc_hmac_init;
zpc_hmac_sign;
zpc_hmac_verify;
zpc_hmac_free;

local: *;
} ZPC_1.2.0;


2 changes: 1 addition & 1 deletion src/aes_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ zpc_aes_key_import(struct zpc_aes_key *aes_key, const unsigned char *buf,
}
} else {
if (aes_key_blob_is_valid_pvsecret_id(aes_key, buf) != 0) {
rc = ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV;
rc = ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV_OR_INVALID_TYPE;
goto ret;
}
}
Expand Down
Loading