diff --git a/man/man8/swtpm_cert.8 b/man/man8/swtpm_cert.8 index ec1cbd0c..fac14fe9 100644 --- a/man/man8/swtpm_cert.8 +++ b/man/man8/swtpm_cert.8 @@ -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 " 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 >" 4 +.IX Item "<--ecc-x >" +The elliptic curve parameter x as string of hex digits. +.IP "<\-\-ecc\-y >" 4 +.IX Item "<--ecc-y >" +The elliptic curve parameter y as string of hex digits. .IP "\fB\-\-exponent " 4 .IX Item "--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=,ST=,L=. 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 diff --git a/man/man8/swtpm_cert.pod b/man/man8/swtpm_cert.pod index 89911176..b0bd837d 100644 --- a/man/man8/swtpm_cert.pod +++ b/man/man8/swtpm_cert.pod @@ -95,6 +95,14 @@ Subject to for example provide the location of the TPM in the format of C=,ST=,L=. 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 diff --git a/src/swtpm_cert/ek-cert.c b/src/swtpm_cert/ek-cert.c index 59fb1074..6f63ff27 100644 --- a/src/swtpm_cert/ek-cert.c +++ b/src/swtpm_cert/ek-cert.c @@ -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)) diff --git a/tests/Makefile.am b/tests/Makefile.am index 7605537d..668f0edb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 diff --git a/tests/test_tpm2_swtpm_cert b/tests/test_tpm2_swtpm_cert new file mode 100755 index 00000000..cc78fa74 --- /dev/null +++ b/tests/test_tpm2_swtpm_cert @@ -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"