stefanberger/swtpm

ECC Endorsement Certificate not generated by swtpm_setup

janwytze opened this issue · 9 comments

Describe the bug

ECC Endorsement Certificate not generated by swtpm_setup while using the --ecc is used.

To Reproduce

  1. Use swtpm_setup --tpmstate /tmp/mytpm2 --ecc --create-ek-cert --create-platform-cert --tpm2 --lock-nvram to setup swtpm.
  2. Run tpm2_getekcertificate -o ek_rsa.crt -o ek_ecc.crt, will output WARN: Ignoring the additional output file since only 1 cert found on NV.

Expected behavior

An EC Endorsement Key Certificate is expected at nv index 0x01C0000A.

Desktop:

  • OS: Debian (Docker)
  • Version bullseye-slim

Versions of relevant components

  • swtpm: 0.8.0 and 0.7.4
  • libtpms: 0.8.8
  • openssl: OpenSSL 1.1.1n 15 Mar 2022
  • gnutls: gnutls-cli 3.7.1

Additional context
The RSA EK certificate is generated, but the ECC is not.

Here's the output of the swtpm_setup run:

$ swtpm_setup --tpmstate ./ --overwrite --ecc --create-ek-cert --create-platform-cert --tpm2 --lock-nvram
Starting vTPM manufacturing as stefanb:stefanb @ Wed 07 Dec 2022 09:48:09 AM EST
TPM is listening on Unix socket.
Successfully created RSA 2048 EK with handle 0x81010001.
  Invoking /usr/share/swtpm/swtpm-localca --type ek --ek e3d36ac7107c42db6567fb344a82724ca27dff57a3c4005bbc4c39f0ea3d1a4132550330b97aa3981f43cc3ed8291310106722c3d818a8a6d43c9ca3dbabffb79679ec400860750e58b395e644fb89d314cc53d565d8f732e32b217d4eefbb872c443e444eddf4af2de6f8864d0da381d59234fc3222f0bac1d5a5da3c4ae865d34d0074a3f6e07c9d54df792583d8107d71e41ddc1060fbe5a0b92760a794b4e34991ccd7f382eb3bffb93cb6d33b8731edad3948757fbf0968b599e467bd6e2195a66a703c4fdfce077cebb3a30855ea6c64e8f89c9c6498223c734f64822842bfca03c948d6e934ca11ef344371094838d008d7b1ac9d8e98f96ac0517f09 --dir /tmp/swtpm_setup.certs.SUW1W1 --tpm-spec-family 2.0 --tpm-spec-level 0 --tpm-spec-revision 164 --tpm-manufacturer id:00001014 --tpm-model swtpm --tpm-version id:20191023 --tpm2 --configfile /home/stefanb/.config/swtpm-localca.conf --optsfile /home/stefanb/.config/swtpm-localca.options
swtpm-localca: Successfully created EK certificate locally.
  Invoking /usr/share/swtpm/swtpm-localca --type platform --ek e3d36ac7107c42db6567fb344a82724ca27dff57a3c4005bbc4c39f0ea3d1a4132550330b97aa3981f43cc3ed8291310106722c3d818a8a6d43c9ca3dbabffb79679ec400860750e58b395e644fb89d314cc53d565d8f732e32b217d4eefbb872c443e444eddf4af2de6f8864d0da381d59234fc3222f0bac1d5a5da3c4ae865d34d0074a3f6e07c9d54df792583d8107d71e41ddc1060fbe5a0b92760a794b4e34991ccd7f382eb3bffb93cb6d33b8731edad3948757fbf0968b599e467bd6e2195a66a703c4fdfce077cebb3a30855ea6c64e8f89c9c6498223c734f64822842bfca03c948d6e934ca11ef344371094838d008d7b1ac9d8e98f96ac0517f09 --dir /tmp/swtpm_setup.certs.SUW1W1 --tpm-spec-family 2.0 --tpm-spec-level 0 --tpm-spec-revision 164 --tpm-manufacturer id:00001014 --tpm-model swtpm --tpm-version id:20191023 --tpm2 --configfile /home/stefanb/.config/swtpm-localca.conf --optsfile /home/stefanb/.config/swtpm-localca.options
swtpm-localca: Successfully created platform certificate locally.
Successfully created NVRAM area 0x1c00002 for RSA 2048 EK certificate.
Successfully created NVRAM area 0x1c08000 for platform certificate.
Successfully created ECC EK with handle 0x81010016.
  Invoking /usr/share/swtpm/swtpm-localca --type ek --ek x=54fdad930ed32a0ad7bb801da48ce7526fb86745af63959e652d42b275231c9caf8c3defc42ab58593897d3384110712,y=e1a7f26bb0bfacca7b2c6540839018457fe7764252032879f70362b5457df0ce3aaef742f40525016cf4c8354098651f,id=secp384r1 --dir /tmp/swtpm_setup.certs.SUW1W1 --tpm-spec-family 2.0 --tpm-spec-level 0 --tpm-spec-revision 164 --tpm-manufacturer id:00001014 --tpm-model swtpm --tpm-version id:20191023 --tpm2 --configfile /home/stefanb/.config/swtpm-localca.conf --optsfile /home/stefanb/.config/swtpm-localca.options
swtpm-localca: Successfully created EK certificate locally.
Successfully created NVRAM area 0x1c00016 for ECC EK certificate.
Successfully activated PCR banks sha256 among sha1,sha256,sha384,sha512.
Successfully authored TPM state.
Ending vTPM manufacturing @ Wed 07 Dec 2022 09:48:09 AM EST

Since swtpm 0.4 swtpm_setup has been creating a NIST-P384/secp384r1 key and stores it at location 0x1c00016. You will have to search through known NVRAM locations to find what is provided.

Documentation is here: https://github.com/stefanberger/swtpm/wiki/Certificates-created-by-swtpm_setup#tpm-2-certificates

TCG docs section 2.2.1.5.1: https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_Credential_Profile_EK_V2.1_R13.pdf

Thanks! I somehow expected a NIST P-256 certificate to be created. The NIST P-256 is also hardcoded in the tpm2_getekcertificate command. Why has the switch from NIST P-256 to NIST P-384 been made?

Why has the switch from NIST P-256 to NIST P-384 been made?

Primarily to get the switch to NIST-P384 behind us asap. I would expect this to come in the future anyway.

Is there a way I can write an P-256 EK key to the NVRAM? I've used the following command to generate one:

$ swtpm_localca --tpm2 --type ek --tpm-manufacturer 00001014 --tpm-model swtpm --tpm-version 20221208 --tpm-spec-family 2.0 --tpm-spec-level 0 --tpm-spec-revision 146 --ek x=$(openssl rand -hex 32 | tr -d '\n '),y=$(openssl rand -hex 32 | tr -d '\n '),id=secp256r1

But I am not able to find a way I can write it from a Dockerfile. The swtpm daemon can not run during a Docker build process, so I can not just write to the tpm using tpm-tools.

I've found the C function that writes the EK, but I cannot just run that from the command line:

static int swtpm_tpm2_write_ek_cert_nvram(struct swtpm *self, gboolean isecc,

But I am not able to find a way I can write it from a Dockerfile. The swtpm daemon can not run during a Docker build process, so I can not just write to the tpm using tpm-tools.

Can you run a script from within the Dockerfile that RUNs swtpm and lets you use the tpm tools to write the cert into it and terminates swtpm in the end?

Executing this script in a single RUN seems to work:

dbus-daemon --fork --system
swtpm socket --tpmstate dir=/tmp/mytpm2 --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init -d
tpm2-abrmd --tcti="swtpm:port=2321" --allow-root &
tpm2_nvdefine 0x01c0000a -C p -a 'ppwrite|writedefine|ppread|ownerread|authread|no_da|platformcreate'
tpm2_nvwrite 0x01c0000a -C p -i ek.cert
tpm2_nvwritelock 0x01c0000a -C p
rm /run/dbus/pid

@stefanberger why does the create certificate does not have a public key included?

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 5 (0x5)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = swtpm-localca
        Validity
            Not Before: Dec 14 12:07:16 2022 GMT
            Not After : Dec 31 23:59:59 9999 GMT
        Subject: CN = unknown
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
            Unable to load Public Key
139884896372032:error:1012606B:elliptic curve routines:EC_POINT_set_affine_coordinates:point is not on curve:../crypto/ec/ec_lib.c:813:
139884896372032:error:10098010:elliptic curve routines:o2i_ECPublicKey:EC lib:../crypto/ec/ec_asn1.c:1200:
139884896372032:error:100D708E:elliptic curve routines:eckey_pub_decode:decode error:../crypto/ec/ec_ameth.c:174:
139884896372032:error:0B09407D:x509 certificate routines:x509_pubkey_decode:public key decode error:../crypto/x509/x_pubkey.c:125:
        X509v3 extensions:
            X509v3 Extended Key Usage: 
                2.23.133.8.1
            X509v3 Subject Alternative Name: critical
                DirName:/2.23.133.2.1=00001014/2.23.133.2.2=swtpm/2.23.133.2.3=20221208
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Directory Attributes: 
                0.0...g....1.0...2.0.......
            X509v3 Authority Key Identifier: 
                keyid:F4:68:DF:93:F4:24:28:6D:82:5B:5F:01:93:0B:C5:E0:9F:DE:CB:76

            X509v3 Key Usage: critical
                Key Agreement
    Signature Algorithm: sha256WithRSAEncryption
         73:08:7c:f0:d0:fa:9f:73:22:f5:fb:f9:70:2e:ab:48:9b:75:
         13:38:b7:86:5a:ac:10:8a:cd:82:2c:d5:40:00:70:08:08:5e:
         16:42:9f:5d:44:78:55:3b:9c:e3:37:4d:99:d3:02:12:e4:7f:
         99:a6:0a:00:db:d0:43:59:7c:2b:c7:b7:18:82:fa:0a:ab:2f:
         ee:de:a4:69:11:71:c5:9b:3d:1d:77:0e:5d:f6:8e:a4:04:4d:
         2b:d1:d5:c8:b7:34:a4:21:cd:a9:e3:e2:91:3e:35:45:15:e9:
         06:57:9f:b1:f5:75:87:d4:a9:e8:e6:e4:2c:6b:74:d7:27:ce:
         fa:ed:75:9d:09:0b:1b:ff:ce:d1:a8:58:5f:f1:6a:f6:49:c5:
         ad:2b:99:b4:b5:17:d7:28:d7:b4:66:e7:8a:42:b1:2e:e7:13:
         a9:02:7e:d7:99:9c:04:98:b4:56:49:d2:f1:a1:da:c3:d0:7d:
         b3:24:ab:5d:88:55:d4:1c:b4:4b:4f:37:4e:a0:28:4e:97:bd:
         f3:db:f6:26:3d:79:0c:52:c7:b2:78:c2:f3:48:81:04:6c:3f:
         53:02:51:97:b3:71:14:ad:af:99:72:73:87:e2:f4:00:d7:07:
         1a:24:73:b9:38:33:05:3a:b4:77:3b:d2:7f:cc:84:96:69:2a:
         31:e6:d0:34:49:1f:be:89:c9:af:40:ca:c4:59:43:73:cf:aa:
         09:94:7c:8a:c6:8a:8d:0a:e1:9d:35:ec:10:6c:ff:58:59:79:
         54:56:70:9f:69:e9:29:1b:3d:64:fb:87:c2:8b:e4:fc:2d:dc:
         bf:60:b7:28:8e:a9:39:67:d2:43:8c:5e:3a:f4:8c:07:e7:63:
         e1:9f:77:cd:ea:d1:93:54:87:b0:27:5a:9c:5f:60:40:81:bc:
         3b:7e:14:2c:2e:20:71:9d:24:35:ed:2f:d7:a1:2a:92:27:dd:
         64:8a:27:79:fe:f3:d6:d3:44:61:b9:02:c0:05:34:4f:b6:79:
         aa:16:ed:3c:24:9b

When I take the logging output from above I get the following for sec384r1:

> mkdir -p /tmp/swtpm_setup.certs.SUW1W1
> /usr/share/swtpm/swtpm-localca --type ek --ek x=54fdad930ed32a0ad7bb801da48ce7526fb86745af63959e652d42b275231c9caf8c3defc42ab58593897d3384110712,y=e1a7f26bb0bfacca7b2c6540839018457fe7764252032879f70362b5457df0ce3aaef742f40525016cf4c8354098651f,id=secp384r1 --dir /tmp/swtpm_setup.certs.SUW1W1 --tpm-spec-family 2.0 --tpm-spec-level 0 --tpm-spec-revision 164 --tpm-manufacturer id:00001014 --tpm-model swtpm --tpm-version id:20191023 --tpm2 --configfile /home/stefanb/.config/swtpm-localca.conf --optsfile /home/stefanb/.config/swtpm-localca.options
> openssl x509 -inform der -in /tmp/swtpm_setup.certs.SUW1W1/ek.cert -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 44 (0x2c)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = swtpm-localca
        Validity
            Not Before: Dec 14 13:37:57 2022 GMT
            Not After : Dec 31 23:59:59 9999 GMT
        Subject: CN = unknown
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (384 bit)
                pub:
                    04:54:fd:ad:93:0e:d3:2a:0a:d7:bb:80:1d:a4:8c:
                    e7:52:6f:b8:67:45:af:63:95:9e:65:2d:42:b2:75:
                    23:1c:9c:af:8c:3d:ef:c4:2a:b5:85:93:89:7d:33:
                    84:11:07:12:e1:a7:f2:6b:b0:bf:ac:ca:7b:2c:65:
                    40:83:90:18:45:7f:e7:76:42:52:03:28:79:f7:03:
                    62:b5:45:7d:f0:ce:3a:ae:f7:42:f4:05:25:01:6c:
                    f4:c8:35:40:98:65:1f
                ASN1 OID: secp384r1
                NIST CURVE: P-384
        X509v3 extensions:
[...]

So this looks good with secp384r1.

I created a prime256v1 (= secp256r1) key:

> openssl ecparam -genkey -out eckey.der -outform der -name prime256v1
> openssl ec -in eckey.der -inform der -text -noout
read EC key
Private-Key: (256 bit)
priv:
    32:c5:b9:70:3b:f1:c2:f6:bc:c3:6c:ca:96:25:96:
    03:85:56:9b:b4:e4:c8:7b:cb:be:f0:e7:61:3f:d1:
    2f:a7
pub:
    04:f8:39:c2:5e:f9:16:27:6b:ff:3f:af:8d:52:a1:
    09:8f:2e:fa:d2:20:b9:83:20:03:a0:ec:25:91:77:
    8b:74:4a:9f:c9:3e:1c:ce:21:f1:7b:fd:0e:5a:1e:
    64:a5:cf:f5:72:4c:6d:0a:e5:66:7d:e4:57:9f:f7:
    ad:93:c3:66:cc
ASN1 OID: prime256v1
NIST CURVE: P-256

Get x and y from it and create cert:

> x=$(echo 'f8:39:c2:5e:f9:16:27:6b:ff:3f:af:8d:52:a1:09:8f:2e:fa:d2:20:b9:83:20:03:a0:ec:25:91:77:8b:74:4a' | sed 's/://g' )
> y=$(echo '9f:c9:3e:1c:ce:21:f1:7b:fd:0e:5a:1e:64:a5:cf:f5:72:4c:6d:0a:e5:66:7d:e4:57:9f:f7:ad:93:c3:66:cc' | sed 's/://g')
> /usr/share/swtpm/swtpm-localca --type ek --ek x=${x},y=${y},id=secp256r1 --dir /tmp/swtpm_setup.certs.SUW1W1 --tpm-spec-family 2.0 --tpm-spec-level 0 --tpm-spec-revision 164 --tpm-manufacturer id:00001014 --tpm-model swtpm --tpm-version id:20191023 --tpm2 --configfile /home/stefanb/.config/swtpm-localca.conf --optsfile /home/stefanb/.config/swtpm-localca.options
> openssl x509 -inform der -in /tmp/swtpm_setup.certs.SUW1W1/ek.cert -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 53 (0x35)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = swtpm-localca
        Validity
            Not Before: Dec 14 23:10:41 2022 GMT
            Not After : Dec 31 23:59:59 9999 GMT
        Subject: CN = unknown
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:f8:39:c2:5e:f9:16:27:6b:ff:3f:af:8d:52:a1:
                    09:8f:2e:fa:d2:20:b9:83:20:03:a0:ec:25:91:77:
                    8b:74:4a:9f:c9:3e:1c:ce:21:f1:7b:fd:0e:5a:1e:
                    64:a5:cf:f5:72:4c:6d:0a:e5:66:7d:e4:57:9f:f7:
                    ad:93:c3:66:cc
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Extended Key Usage:
                2.23.133.8.1
[...]

So the output is as expected for secp256r1. I would suggest to check your input or work with a real key's x and y parameters rather than random numbers.

Edit: OpenSSL checks whether the points are on the curve and bails out if they are not - this is due to the random numbers. The certificate is basically useless and shouldn't be created though GnuTLS in this doesn't seem to care creating this certificate. For as long as GnuTLS checks that the point is on the curve when it does math with it, that's important.

Thanks!! I made a simple bash script to extract the X and Y from the P256 EK:

tpm2_createek -G ecc -c - -u ek.pub -f der
PUBLIC_KEY=$(openssl ec -pubin -in ek.pub -inform DER -pubout -text | head -n 7 | tail -n 5 | tr -d '[:space:]:' | tail -c128)
PUBLIC_KEY_X=$(echo -n $PUBLIC_KEY | head -c64)
PUBLIC_KEY_Y=$(echo -n $PUBLIC_KEY | tail -c64)
swtpm_localca --tpm2 --type ek --tpm-manufacturer 00001014 --tpm-model swtpm --tpm-version 20221208 --tpm-spec-family 2.0 --tpm-spec-level 0 --tpm-spec-revision 146 --ek x=$PUBLIC_KEY_X,y=$PUBLIC_KEY_Y,id=secp256r1

tpm2_nvdefine 0x01c0000a -C p -a 'ppwrite|writedefine|ppread|ownerread|authread|no_da|platformcreate' -s $(stat --printf="%s" ek.cert)
tpm2_nvwrite 0x01c0000a -C p -i ek.cert
tpm2_nvwritelock 0x01c0000a -C p