Skip to content

Commit

Permalink
swtpm: Modify custom profile when FIPS is enabled
Browse files Browse the repository at this point in the history
When FIPS is enabled on the host and the 'custom' profile is chosen
then remove all (currently) known algorithms disabled by FIPS so that
FIPS does not need to be disabled in the OpenSSL instance. Also set
or adjust minimum key sizes for EC and RSA keys.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
  • Loading branch information
stefanberger committed Aug 22, 2024
1 parent 5677f2c commit f373b17
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/swtpm/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ noinst_HEADERS = \
options.h \
daemonize.h \
pidfile.h \
profile.h \
seccomp_profile.h \
server.h \
swtpm_aes.h \
Expand Down Expand Up @@ -49,6 +50,7 @@ libswtpm_libtpms_la_SOURCES = \
mainloop.c \
options.c \
pidfile.c \
profile.c \
seccomp_profile.c \
server.c \
swtpm_aes.c \
Expand Down
70 changes: 70 additions & 0 deletions src/swtpm/check_algos.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

#include "config.h"

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

#include "check_algos.h"
Expand Down Expand Up @@ -404,6 +406,24 @@ static const struct algorithms_tests {
}
};

static const struct fips_disabled {
const char *name;
ssize_t name_len; // -1 for full name, prefix matching otherwise
} ossl_fips_disabled_algorithms[] = {
#define ENTRY(NAME, NAME_LEN) { .name = NAME, .name_len = NAME_LEN, }
ENTRY("camellia", -1),
ENTRY("camellia-min-size=", 18),
ENTRY("tdes", -1),
ENTRY("tdes-min-size=", 14),
ENTRY("rsaes", -1),
ENTRY("ecc-nist-p192", -1),
ENTRY("ecc-bn", -1),
ENTRY("ecc-bn-p", 8), // p256, p638
ENTRY("ecc-sm2-p", 9), // p256
ENTRY(NULL, 0)
#undef ENTRY
};

/* list of minimum required key sizes for FIPS */
static const struct key_sizes {
const char **names; // all of these must be found enabled in profile
Expand Down Expand Up @@ -515,3 +535,53 @@ unsigned int ossl_algorithms_are_disabled(const gchar *const*algorithms,
disabled_filter,
stop_on_first_disabled);
}

/*
* Remove those algorithms in the given array that are disabled by FIPS and
* set or adjust key lengths to minimum required sizes for FIPS.
*/
int ossl_remove_fips_disabled_algorithms(gchar ***algorithms)
{
unsigned long v;
size_t i, l;
ssize_t j;
gchar *old;

/* remove all unsupported algorithms */
for (i = 0; ossl_fips_disabled_algorithms[i].name != NULL; i++)
strv_remove(*algorithms,
ossl_fips_disabled_algorithms[i].name,
ossl_fips_disabled_algorithms[i].name_len);

/* set/adjust min. key sizes */
for (i = 0; fips_key_sizes[i].keyword; i++) {
l = strlen(fips_key_sizes[i].keyword);
j = strv_strncmp((const gchar *const*)*algorithms, fips_key_sizes[i].keyword, l);
if (j >= 0) {
/* key size large enough as indicated? */
v = strtoul(&((*algorithms)[j])[l], NULL, 10);
if (v >= fips_key_sizes[i].min_size)
continue;

/* need to adjust min key size */
old = (*algorithms)[j];
} else {
/* append to strv */
j = g_strv_length(*algorithms);
*algorithms = g_realloc(*algorithms,
sizeof(char *) * (j + 1 + 1));
(*algorithms)[j + 1] = NULL;
old = NULL;
}

if (asprintf(&((*algorithms)[j]), "%s%u",
fips_key_sizes[i].keyword,
fips_key_sizes[i].min_size) < 0) {
(*algorithms)[j] = old;
return 1;
}
g_free(old);
}

return 0;
}
2 changes: 2 additions & 0 deletions src/swtpm/check_algos.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,6 @@ unsigned int ossl_algorithms_are_disabled(const gchar *const*algorithms,
#define FIX_ENABLE_SHA1_SIGNATURES (1 << 1) /* fix by setting OPENSSL_ENABLE_SHA1_SIGNATURES=1 */
#define FIX_DISABLE_CONFIG (1 << 2) /* fix by modifying openssl config (how?) */

int ossl_remove_fips_disabled_algorithms(gchar ***algorithms);

#endif /* _SWTPM_CHECK_ALGOS_H_ */
6 changes: 6 additions & 0 deletions src/swtpm/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
#include "seccomp_profile.h"
#include "tpmlib.h"
#include "mainloop.h"
#include "profile.h"
#include "swtpm_utils.h"

/* --log %s */
static const OptionDesc logging_opt_desc[] = {
Expand Down Expand Up @@ -1458,6 +1460,9 @@ static int parse_profile_options(char *options, char **json_profile)
}
}

if (profile_remove_fips_disabled_algorithms(json_profile) == 1)
goto error;

option_values_free(ovs);

return 0;
Expand All @@ -1467,6 +1472,7 @@ static int parse_profile_options(char *options, char **json_profile)
"Out of memory to create JSON profile\n");

error:
SWTPM_G_FREE(*json_profile);
option_values_free(ovs);
free(error);

Expand Down
68 changes: 68 additions & 0 deletions src/swtpm/profile.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: BSD-3-Clause */

/*
* profile.c: Functions for handling profiles
*
* Author: Stefan Berger, stefanb@linux.ibm.com
*
* Copyright (c) IBM Corporation, 2024
*/

#include "config.h"

#include <stdio.h>

#include "profile.h"
#include "utils.h"
#include "swtpm_utils.h"
#include "check_algos.h"

/*
* Remove algorithms disabled by FIPS from the given JSON profile but only do
* this if this is the 'custom' profile.
*
* @json_profile: Pointer to the string with the JSON profile
*
* Return values:
* 0 : no error
* 1 : fatal error
* 2 : this is not the 'custom' profile
*/
int profile_remove_fips_disabled_algorithms(char **json_profile)
{
g_autofree gchar *info_data = NULL;
g_autofree gchar *value = NULL;
g_auto(GStrv) algorithms = NULL;
int ret;

ret = json_get_map_key_value(*json_profile, "Name", &value);
if (ret || !value || strcmp(value, "custom"))
return 2;

SWTPM_G_FREE(value);
ret = json_get_map_key_value(*json_profile, "Algorithms", &value);
if (ret == 1)
return 1;

if (ret == 2) {
info_data = TPMLIB_GetInfo(TPMLIB_INFO_RUNTIME_ALGORITHMS);

ret = json_get_submap_value(info_data, "RuntimeAlgorithms", "Implemented",
&value);
if (ret)
return 1;
}
algorithms = g_strsplit(value, ",", -1);
if (ossl_remove_fips_disabled_algorithms(&algorithms))
return 1;

g_free(value);
value = g_strjoinv(",", algorithms);

/* put algorithms into JSON */
ret = json_set_map_key_value(json_profile, "Algorithms", value);
if (ret)
return 1;

return 0;
}
16 changes: 16 additions & 0 deletions src/swtpm/profile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: BSD-3-Clause */

/*
* profile.h: Header for profile.c
*
* Author: Stefan Berger, stefanb@linux.ibm.com
*
* Copyright (c) IBM Corporation, 2024
*/

#ifndef SWTPM_PROFILE_H
#define SWTPM_PROFILE_H

int profile_remove_fips_disabled_algorithms(char **json_profile);

#endif /* SWTPM_PROFILE_H */
103 changes: 103 additions & 0 deletions src/swtpm/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,85 @@ ssize_t read_eintr(int fd, void *buffer, size_t buflen)
}
}

/*
* Get the value of a map's key.
*
* Returns:
* 0 : success
* 1 : failure to parse the JSON input
* 2 : could not find the key
*/
int json_get_map_key_value(const char *json_input,
const char *key, char **value)
{
g_autoptr(GError) error = NULL;
g_autoptr(JsonParser) jp = NULL;
g_autoptr(JsonReader) jr = NULL;
JsonNode *root;

jp = json_parser_new();
if (!json_parser_load_from_data(jp, json_input, -1, &error)) {
logprintf(STDERR_FILENO,
"Could not parse JSON '%s': %s\n", json_input, error->message);
return 1;
}

root = json_parser_get_root(jp);
jr = json_reader_new(root);

if (!json_reader_read_member(jr, key))
return 2;

*value = g_strdup(json_reader_get_string_value(jr));
if (*value == NULL) {
/* value not a string */
logprintf(STDERR_FILENO,
"'%s' in JSON map is not a string\n", key);
return 1;
}

return 0;
}

/*
* Set the value of a map's key and return the new string
*
* Returns:
* 0 : success
* 1 : fatal failure
*/
int json_set_map_key_value(char **json_string,
const char *key, const char *value)
{
g_autoptr(JsonParser) jp = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(JsonGenerator) jg;
JsonObject *jo;
JsonNode *root;

jg = json_generator_new();
if (!jg)
return 1;

jp = json_parser_new();
if (!json_parser_load_from_data(jp, *json_string, -1, &error)) {
logprintf(STDERR_FILENO,
"Could not parse JSON '%s': %s\n", *json_string, error->message);
return 1;
}

root = json_parser_get_root(jp);
json_generator_set_root(jg, root);

jo = json_node_get_object(root);
json_object_set_string_member(jo, key, value);

g_free(*json_string);
*json_string = json_generator_to_data(jg, NULL);

return 0;
}

/*
* In the given JSON map find a map with name @field_name and then
* access the field @field_name2 in this map and return its value.
Expand Down Expand Up @@ -440,3 +519,27 @@ gboolean strv_contains_all(const gchar *const*haystack, const gchar *const*needl
}
return true;
}

gboolean strv_remove(gchar **array, const gchar *toremove, ssize_t len)
{
unsigned int num = 0;
size_t i = 0, j;

while (array[i]) {
if ((len < 0 && strcmp(array[i], toremove) == 0) ||
(strncmp(array[i], toremove, len) == 0)) {
g_free(array[i]);

j = i;
do {
j++;
array[j - 1] = array[j];
} while(array[j]);

num++;
} else {
i++;
}
}
return num;
}
6 changes: 6 additions & 0 deletions src/swtpm/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,15 @@ ssize_t read_eintr(int fd, void *buffer, size_t buflen);

int json_get_submap_value(const char *json_input, const char *field_name,
const char *field_name2, char **value);
int json_get_map_key_value(const char *json_input,
const char *key, char **value);
int json_set_map_key_value(char **json_input,
const char *key, const char *value);

ssize_t strv_strncmp(const gchar *const*str_array, const gchar *s, size_t n);

gboolean strv_contains_all(const gchar *const*haystack, const gchar *const*needles);

gboolean strv_remove(gchar **array, const gchar *toremove, ssize_t len);

#endif /* _SWTPM_UTILS_H_ */

0 comments on commit f373b17

Please sign in to comment.