mirror of
https://github.com/stefanberger/swtpm.git
synced 2026-08-12 17:32:44 +00:00
swtpm_cert: Add support for TPM2
TPM2 allows the primary key to also be a signing key, so in case --tpm2 is provided, --allow-signing can be provided as well in case the primary can also be used for signing operations. We use SHA256 for the signing algorithm when TPM 2 is being used. Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
parent
8fcec541f8
commit
e5ffc74dc8
@ -1,4 +1,4 @@
|
||||
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
|
||||
.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.31)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
@ -133,7 +133,7 @@
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "swtpm_cert 8"
|
||||
.TH swtpm_cert 8 "2014-09-23" "swtpm" ""
|
||||
.TH swtpm_cert 8 "2016-12-20" "swtpm" ""
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
@ -162,6 +162,12 @@ The public key (\s-1EK\s0) in \s-1PEM\s0 format.
|
||||
.IX Item "--modulus <hex digits>"
|
||||
The modulus of the public key as a string of hex digits. This option
|
||||
can be used in place of the \-\-pubkey option.
|
||||
.IP "<\-\-ecc\-x <hex digits>>" 4
|
||||
.IX Item "<--ecc-x <hex digits>>"
|
||||
The elliptic curve parameter x as string of hex digits.
|
||||
.IP "<\-\-ecc\-y <hex digits>>" 4
|
||||
.IX Item "<--ecc-y <hex digits>>"
|
||||
The elliptic curve parameter y as string of hex digits.
|
||||
.IP "\fB\-\-exponent <exponent\fR>" 4
|
||||
.IX Item "--exponent <exponent>"
|
||||
The exponent of the public key. By default 0x10001 is assumed.
|
||||
@ -210,6 +216,12 @@ The platform's version.
|
||||
Subject to for example provide the location of the \s-1TPM\s0 in the format of
|
||||
C=<country>,ST=<state>,L=<location>.
|
||||
Note that the location must no contain any spaces.
|
||||
.IP "\fB\-\-tpm2\fR" 4
|
||||
.IX Item "--tpm2"
|
||||
Issue \s-1TPM 2\s0 compliant certificates.
|
||||
.IP "\fB\-\-allow\-signing\fR" 4
|
||||
.IX Item "--allow-signing"
|
||||
Create an \s-1EK\s0 that can also be used for signing. This option requires \-\-tpm2.
|
||||
.IP "\fB\-\-help, \-h\fR" 4
|
||||
.IX Item "--help, -h"
|
||||
Display the help screen
|
||||
|
||||
@ -95,6 +95,14 @@ Subject to for example provide the location of the TPM in the format of
|
||||
C=<country>,ST=<state>,L=<location>.
|
||||
Note that the location must no contain any spaces.
|
||||
|
||||
=item B<--tpm2>
|
||||
|
||||
Issue TPM 2 compliant certificates.
|
||||
|
||||
=item B<--allow-signing>
|
||||
|
||||
Create an EK that can also be used for signing. This option requires --tpm2.
|
||||
|
||||
=item B<--help, -h>
|
||||
|
||||
Display the help screen
|
||||
|
||||
@ -64,6 +64,10 @@ enum cert_type_t {
|
||||
CERT_TYPE_AIK,
|
||||
};
|
||||
|
||||
/* some flags */
|
||||
#define CERT_TYPE_TPM2_F 1
|
||||
#define ALLOW_SIGNING_F 2 /* EK can be used for signing */
|
||||
|
||||
extern const ASN1_ARRAY_TYPE tpm_asn1_tab[];
|
||||
|
||||
ASN1_TYPE _tpm_asn;
|
||||
@ -124,6 +128,9 @@ usage(const char *prg)
|
||||
" C=US,ST=NY,L=NewYork; not used with TPM1.2\n"
|
||||
"--add-header : Add the TCG certificate header describing\n"
|
||||
" a TCG_PCCLIENT_STORED_CERT for TPM1.2 NVRAM\n"
|
||||
"--tpm2 : Issue a TPM 2 compliant certificate\n"
|
||||
"--allow-signing : The EK of a TPM 2 allows signing;\n"
|
||||
" requires --tpm2\n"
|
||||
"--version : Display version and exit\n"
|
||||
"--help : Display this help screen and exit\n"
|
||||
"\n",
|
||||
@ -468,6 +475,43 @@ cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
create_platf_manufacturer_info(const char *manufacturer,
|
||||
const char *platf_model,
|
||||
const char *platf_version,
|
||||
gnutls_datum_t *asn1)
|
||||
{
|
||||
ASN1_TYPE at = ASN1_TYPE_EMPTY;
|
||||
int err;
|
||||
|
||||
err = asn_init();
|
||||
if (err != ASN1_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = build_platf_manufacturer_info(&at, manufacturer,
|
||||
platf_model, platf_version);
|
||||
if (err != ASN1_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = encode_asn1(asn1, at);
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "size=%d\n", asn1->size);
|
||||
unsigned int i = 0;
|
||||
for (i = 0; i < asn1->size; i++) {
|
||||
fprintf(stderr, "%02x ", asn1->data[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
asn1_delete_structure(&at);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
create_tpm_and_platform_manuf_info(
|
||||
const char *tpm_manufacturer,
|
||||
@ -767,6 +811,7 @@ main(int argc, char *argv[])
|
||||
unsigned char *modulus_bin = NULL;
|
||||
int modulus_len = 0;
|
||||
gnutls_datum_t datum = { NULL, 0}, out = { NULL, 0};
|
||||
gnutls_digest_algorithm_t hashAlgo = GNUTLS_DIG_SHA1;
|
||||
int serial = 1;
|
||||
time_t now;
|
||||
int err;
|
||||
@ -793,6 +838,7 @@ main(int argc, char *argv[])
|
||||
char *spec_family = NULL;
|
||||
long int spec_level = ~0;
|
||||
long int spec_revision = ~0;
|
||||
int flags = 0;
|
||||
|
||||
i = 1;
|
||||
while (i < argc) {
|
||||
@ -970,6 +1016,10 @@ main(int argc, char *argv[])
|
||||
write_pem = true;
|
||||
} else if (!strcmp(argv[i], "--add-header")) {
|
||||
add_header = true;
|
||||
} else if (!strcmp(argv[i], "--tpm2")) {
|
||||
flags |= CERT_TYPE_TPM2_F;
|
||||
} else if (!strcmp(argv[i], "--allow-signing")) {
|
||||
flags |= ALLOW_SIGNING_F;
|
||||
} else if (!strcmp(argv[i], "--version")) {
|
||||
versioninfo(argv[0]);
|
||||
exit(0);
|
||||
@ -983,7 +1033,10 @@ main(int argc, char *argv[])
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
if (flags & CERT_TYPE_TPM2_F)
|
||||
hashAlgo = GNUTLS_DIG_SHA256;
|
||||
|
||||
ser_number = htonl(serial);
|
||||
|
||||
if (pubkey_filename == NULL && modulus_bin == NULL) {
|
||||
@ -1140,7 +1193,7 @@ if (_err != GNUTLS_E_SUCCESS) { \
|
||||
gnutls_strerror(err))
|
||||
|
||||
/* 3.5.6 Subject -- must be empty for TPM 1.2 */
|
||||
if (subject && false) {
|
||||
if (subject && (flags & CERT_TYPE_TPM2_F)) {
|
||||
err = gnutls_x509_crt_set_dn(crt, subject, &error);
|
||||
CHECK_GNUTLS_ERROR(err,
|
||||
"Could not set DN on CRT: %s\n"
|
||||
@ -1172,7 +1225,7 @@ if (_err != GNUTLS_E_SUCCESS) { \
|
||||
}
|
||||
|
||||
/* 3.5.8 Certificate Policies -- skip since not mandated */
|
||||
/* 3.5.9 Subject Alternative Names -- missing code */
|
||||
/* 3.5.9 Subject Alternative Names */
|
||||
switch (certtype) {
|
||||
case CERT_TYPE_EK:
|
||||
err = create_tpm_manufacturer_info(tpm_manufacturer, tpm_model,
|
||||
@ -1183,15 +1236,29 @@ if (_err != GNUTLS_E_SUCCESS) { \
|
||||
}
|
||||
break;
|
||||
case CERT_TYPE_PLATFORM:
|
||||
err = create_tpm_and_platform_manuf_info(tpm_manufacturer, tpm_model,
|
||||
tpm_version,
|
||||
platf_manufacturer,
|
||||
platf_model, platf_version,
|
||||
if (flags & CERT_TYPE_TPM2_F) {
|
||||
err = create_platf_manufacturer_info(platf_manufacturer,
|
||||
platf_model,
|
||||
platf_version,
|
||||
&datum);
|
||||
if (err) {
|
||||
fprintf(stderr, "Could not create TPM and platform manufacturer "
|
||||
"info");
|
||||
goto cleanup;
|
||||
if (err) {
|
||||
fprintf(stderr, "Could not create platform manufacturer "
|
||||
"info");
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
err = create_tpm_and_platform_manuf_info(tpm_manufacturer,
|
||||
tpm_model,
|
||||
tpm_version,
|
||||
platf_manufacturer,
|
||||
platf_model,
|
||||
platf_version,
|
||||
&datum);
|
||||
if (err) {
|
||||
fprintf(stderr, "Could not create TPM and platform "
|
||||
"manufacturer info");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CERT_TYPE_AIK:
|
||||
@ -1268,7 +1335,15 @@ if (_err != GNUTLS_E_SUCCESS) { \
|
||||
switch (certtype) {
|
||||
case CERT_TYPE_EK:
|
||||
case CERT_TYPE_PLATFORM:
|
||||
key_usage = GNUTLS_KEY_KEY_ENCIPHERMENT;
|
||||
if (flags & CERT_TYPE_TPM2_F) {
|
||||
if (flags & ALLOW_SIGNING_F) {
|
||||
key_usage = GNUTLS_KEY_DIGITAL_SIGNATURE;
|
||||
} else {
|
||||
key_usage = GNUTLS_KEY_KEY_ENCIPHERMENT;
|
||||
}
|
||||
} else {
|
||||
key_usage = GNUTLS_KEY_KEY_ENCIPHERMENT;
|
||||
}
|
||||
break;
|
||||
case CERT_TYPE_AIK:
|
||||
key_usage = GNUTLS_KEY_DIGITAL_SIGNATURE;
|
||||
@ -1333,7 +1408,7 @@ if (_err != GNUTLS_E_SUCCESS) { \
|
||||
gnutls_strerror(err))
|
||||
|
||||
/* sign cert */
|
||||
err = gnutls_x509_crt_sign2(crt, sigcert, sigkey, GNUTLS_DIG_SHA1, 0);
|
||||
err = gnutls_x509_crt_sign2(crt, sigcert, sigkey, hashAlgo, 0);
|
||||
CHECK_GNUTLS_ERROR(err, "Could not sign the CRT: %s\n",
|
||||
gnutls_strerror(err))
|
||||
|
||||
|
||||
@ -57,7 +57,8 @@ endif
|
||||
|
||||
if WITH_GNUTLS
|
||||
TESTS += \
|
||||
test_swtpm_cert
|
||||
test_swtpm_cert \
|
||||
test_tpm2_swtpm_cert
|
||||
if WITH_SWTPM_SETUP
|
||||
TESTS += \
|
||||
test_swtpm_setup_create_cert
|
||||
|
||||
137
tests/test_tpm2_swtpm_cert
Executable file
137
tests/test_tpm2_swtpm_cert
Executable file
@ -0,0 +1,137 @@
|
||||
#!/bin/bash
|
||||
|
||||
# For the license, see the LICENSE file in the root directory.
|
||||
|
||||
DIR=$(dirname "$0")
|
||||
ROOT=${DIR}/..
|
||||
SWTPM_CERT=${ROOT}/src/swtpm_cert/swtpm_cert
|
||||
|
||||
cert=$(mktemp)
|
||||
|
||||
trap "cleanup" SIGTERM EXIT
|
||||
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
rm -f ${cert}
|
||||
}
|
||||
|
||||
function check_cert_size()
|
||||
{
|
||||
local cert="$1"
|
||||
local exp="$2"
|
||||
|
||||
# Unfortunately different GnuTLS versions may create certs of different
|
||||
# sizes; deactivate this test for now
|
||||
return
|
||||
|
||||
local size=$(stat -c%s ${cert} 2>/dev/null)
|
||||
if [ $size -ne $exp ]; then
|
||||
echo "Warning: Certificate file has unexpected size."
|
||||
echo " Expected: $exp; found: $size"
|
||||
fi
|
||||
}
|
||||
|
||||
${SWTPM_CERT} \
|
||||
--tpm2 \
|
||||
--allow-signing \
|
||||
--signkey ${DIR}/data/signkey.pem \
|
||||
--issuercert ${DIR}/data/issuercert.pem \
|
||||
--out-cert ${cert} \
|
||||
--modulus 'b9dda830729de58f9f5bed2b3b9394ad4ec5afb9c390b89a3337250cbc575cfc8f31f7ffd3f05f4155076f7d1605381cd281b7f147b801154e4f89ee529fe36eae50f79561850e5b63037edaacbb390ea3fcd037e674fb179e3c5afe31214d78a756ca44cc6cf25421b51420ede548310c92b08a513ccc62fd0ef45dcf6546f6e865be6a661d045d1c47b60b428d11dc97cb9f35ee7c385bb20320934b015f8014e8fb19851c2af307e1e64648c142175e40b60615dc494fdb09ea5d5a6f3273b65a241e3cf30cc449b9fb3f900d1ed4be967b32b16f95a1d732dbfa143eaa1c2017556117f70faee5d77f836705d05405361ad5871a32161fa5a1234cfab497' \
|
||||
--days 3650 \
|
||||
--pem \
|
||||
--tpm-manufacturer IBM --tpm-model swtpm-libtpms --tpm-version 1.2 \
|
||||
--tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: ${SWTPM_CERT} returned error code."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#expecting size to be constant
|
||||
check_cert_size "${cert}" 1224
|
||||
|
||||
# truncate result file
|
||||
echo -n > ${cert}
|
||||
echo "Test 1: OK"
|
||||
|
||||
${SWTPM_CERT} \
|
||||
--tpm2 \
|
||||
--signkey ${DIR}/data/signkey.pem \
|
||||
--issuercert ${DIR}/data/issuercert.pem \
|
||||
--out-cert ${cert} \
|
||||
--modulus 'b9dda830729de58f9f5bed2b3b9394ad4ec5afb9c390b89a3337250cbc575cfc8f31f7ffd3f05f4155076f7d1605381cd281b7f147b801154e4f89ee529fe36eae50f79561850e5b63037edaacbb390ea3fcd037e674fb179e3c5afe31214d78a756ca44cc6cf25421b51420ede548310c92b08a513ccc62fd0ef45dcf6546f6e865be6a661d045d1c47b60b428d11dc97cb9f35ee7c385bb20320934b015f8014e8fb19851c2af307e1e64648c142175e40b60615dc494fdb09ea5d5a6f3273b65a241e3cf30cc449b9fb3f900d1ed4be967b32b16f95a1d732dbfa143eaa1c2017556117f70faee5d77f836705d05405361ad5871a32161fa5a1234cfab497' \
|
||||
--days 3650 \
|
||||
--subject "OU=foo,L=NewYork,ST=NY,C=US" \
|
||||
--pem \
|
||||
--tpm-manufacturer IBM --tpm-model swtpm-libtpms --tpm-version 1.2 \
|
||||
--tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: ${SWTPM_CERT} returned error code."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#expecting size to be constant
|
||||
check_cert_size "${cert}" 1302
|
||||
|
||||
# truncate result file
|
||||
echo -n > ${cert}
|
||||
echo "Test 2: OK"
|
||||
|
||||
${SWTPM_CERT} \
|
||||
--tpm2 \
|
||||
--signkey ${DIR}/data/signkey.pem \
|
||||
--issuercert ${DIR}/data/issuercert.pem \
|
||||
--out-cert ${cert} \
|
||||
--pubkey ${DIR}/data/pubek.pem \
|
||||
--days 3650 \
|
||||
--subject "OU=foo,L=NewYork,ST=NY,C=US" \
|
||||
--pem \
|
||||
--tpm-manufacturer IBM --tpm-model swtpm-libtpms --tpm-version 1.2 \
|
||||
--tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: ${SWTPM_CERT} returned error code."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#expecting size to be constant
|
||||
check_cert_size "${cert}" 1367
|
||||
|
||||
# truncate result file
|
||||
#certtool --certificate-info --infile ${cert}
|
||||
echo -n > ${cert}
|
||||
echo "Test 3: OK"
|
||||
|
||||
|
||||
###################### Platform Certificate #####################
|
||||
|
||||
${SWTPM_CERT} \
|
||||
--tpm2 \
|
||||
--type platform \
|
||||
--signkey ${DIR}/data/signkey.pem \
|
||||
--issuercert ${DIR}/data/issuercert.pem \
|
||||
--pubkey ${DIR}/data/pubek.pem \
|
||||
--out-cert ${cert} \
|
||||
--days 3650 \
|
||||
--subject "OU=foo,L=NewYork,ST=NY,C=US" \
|
||||
--pem \
|
||||
--tpm-manufacturer IBM --tpm-model swtpm-libtpms --tpm-version 1.2 \
|
||||
--platform-manufacturer Fedora \
|
||||
--platform-model QEMU \
|
||||
--platform-version 2.1
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: ${SWTPM_CERT} returned error code."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#expecting size to be constant
|
||||
check_cert_size "${cert}" 1411
|
||||
|
||||
# truncate result file
|
||||
#certtool --certificate-info --infile ${cert}
|
||||
echo -n > ${cert}
|
||||
echo "Test 4: OK"
|
||||
Loading…
Reference in New Issue
Block a user