#+TITLE: TPM for OpenPGP
#+HTML_HEAD: <link rel="stylesheet" href="https://sandyuraz.com/styles/org.min.css">
#+PROPERTY: header-args :tangle yes :exports both

This crate implements bindings so that TPM chips can be used with
OpenPGP applications.

* Basic key usage

First, we assume that we'll use TPM 2 simulator package. If you want
to test on real device set ~TCTI~ to ~device:/dev/tpmrm0~.

#+begin_src sh
set -e
set -o pipefail

tpm_server &

sleep 5

tpm2_startup -c -T mssim

TCTI=mssim:
PATH=$PATH:./target/debug

# Increase verbosity of commands
export RUST_LOG=info
#+end_src

To generate a number of random bytes using the specified TPM:

#+begin_src sh :var TCTI="device:/dev/tpmrm0" PATH="./target/debug" :exports both
draw-bytes --tcti $TCTI
#+end_src

#+RESULTS:
: 46d2f84712cefc51c8bc124354f7daa0fecd2f6066963ab15b6b50a63248dd90

** Creating persistent keys

This crate uses descriptive documents for configuring key properties.

*** RSA

The following configuration creates RSA-2048 signing key and persists
it at the handle ~0x01000027~. ~123~ is used as a sample auth value (PIN).

#+BEGIN_SRC yaml :tangle key.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000027
  algo:
    RSA:
      bits: 2048
  capabilities:
    - sign
  auth: 123
#+END_SRC

The key description (~key.yml~) is being read by the ~create-key~
binary that persists that key:

#+BEGIN_SRC sh
create-key -f key.yml
#+END_SRC

Presence of the key can be checked by using ~tpm2_getcap
handles-persistent~ command from TSS suite of tools.

And the same file is used to retrieve it again using ~get-key~ binary:

#+BEGIN_SRC sh
get-key -f key.yml
#+END_SRC

#+RESULTS:
: public_key:
:   RSA:
:     bytes:  
: manu: 1229081888
: name: 000b6c69b7da1d7391d0046fa805915520adb39bb419554c881cfdfee56b69d6d68d

We can turn this into a not quite valid OpenPGP certificate using the
~get-openpgp-key~ binary:

#+BEGIN_SRC sh
get-openpgp-key -f key.yml
#+END_SRC

#+RESULTS:
: -----BEGIN PGP PUBLIC KEY BLOCK-----
: 
: xsBNBAAAAAABCADYAHeYhUkqnjcSiAu67+NINl7/ObsPq/kiYuAbPZbvxyOrae7i
: 4yoMpGh+BWIYL/Q0PL063lCRvLTiIMAsx0HDl2Xlo4SQxp3ae/rYrgsbUh7Efzf6
: +zsFcGGBVUQe1RbWseDAmpcGWAClTZg3/Eqe87nVaLTvac5Ns2CXwxs1d150PEP+
: 8ZWR8M9ERRH1Yess7MPF88GJEuoGBQACbDOFSGgs6JQxPlSEbg5LPkISUMmoROZ8
: 5HDpCfS3ofBluDw5EWRSj9EuCkWBNAUA4saGM0IwS161bfCecIPAqCaFPD7PQ2KU
: 4sBq1wkOdLpveOdFDGAC2A7hXn6h82S8OfBxABEBAAE=
: =bZUC
: -----END PGP PUBLIC KEY BLOCK-----


Creating decryption key is just as strightforward:

#+BEGIN_SRC yaml :tangle decryption.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000018
  algo:
    RSA:
      bits: 2048
  capabilities:
    - decrypt
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f decryption.yml
#+END_SRC

*** EC: NIST-P256

The following configuration creates NIST-P256 signing key and persists
it at the handle ~0x01000127~. ~123~ is used as a sample auth value (PIN).

#+BEGIN_SRC yaml :tangle key-nist-p256.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000127
  algo:
    EC:
      curve: NIST-P256
  capabilities:
    - sign
  auth: 123
#+END_SRC

The key description (~key-nist-p256.yml~) is being read by the ~create-key~
binary that persists that key:

#+BEGIN_SRC sh
create-key -f key-nist-p256.yml
#+END_SRC

Presence of the key can be checked by using ~tpm2_getcap
handles-persistent~ command from TSS suite of tools.

And the same file is used to retrieve it again using ~get-key~ binary:

#+BEGIN_SRC sh
get-key -f key-nist-p256.yml
#+END_SRC

#+RESULTS:
: public_key:
:   EC:
:     x: b998133e8339fc3680808ef64c41fdceb791ccc0c4e1906b99bfd134e59be38c
:     y: 830dc6c759441d30c843f1d5e27d5afa65dd6190359498bd57d3b5c984704ae9
: manu: 1229081888
: name: 000b064deda7eaebd1f0ca982fc4adcc20d6c90d64d72de5277f072ba3633de848ba

Creating decryption key is just as strightforward:

#+BEGIN_SRC yaml :tangle decryption-nist-p256.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000118
  algo:
    EC:
      curve: NIST-P256
  capabilities:
    - decrypt
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f decryption-nist-p256.yml
#+END_SRC

*** EC: NIST-P384

The following configuration creates NIST-P384 signing key and persists
it at the handle ~0x01000227~. ~123~ is used as a sample auth value (PIN).

#+BEGIN_SRC yaml :tangle key-nist-p384.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000227
  algo:
    EC:
      curve: NIST-P384
  capabilities:
    - sign
  auth: 123
#+END_SRC

The key description (~key-nist-p384.yml~) is being read by the ~create-key~
binary that persists that key:

#+BEGIN_SRC sh
create-key -f key-nist-p384.yml
#+END_SRC

Presence of the key can be checked by using ~tpm2_getcap
handles-persistent~ command from TSS suite of tools.

And the same file is used to retrieve it again using ~get-key~ binary:

#+BEGIN_SRC sh
get-key -f key-nist-p384.yml
#+END_SRC

#+RESULTS:
: public_key:
:   EC:
:     x: b5d6885b6774c8a1a944b4559f26b931df031c893bc05139fc54c876b01401253ecea26ea17fa70c017bb5b4d6bb5885
:     y: d29cda6bc9742e49b030db3ec9004217ba8fd052b7d26fc7bddbbe7cb9854fabf7cdc5978ebb8fed9383d387a07bcdf9
: manu: 1229081888
: name: 000b8e28e3d95570efc686bb21f5329a658fe09321d38b496fe02749251e28a07ef5

Creating decryption key is just as strightforward:

#+BEGIN_SRC yaml :tangle decryption-nist-p384.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000218
  algo:
    EC:
      curve: NIST-P384
  capabilities:
    - decrypt
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f decryption-nist-p384.yml
#+END_SRC

** Creating non-persistent keys

Non persistent keys allow using unlimited number of keys that never
use up TPM memory.

*** RSA

Keys need to be wrapped using a key parent that itself needs to be
persistent:

#+BEGIN_SRC yaml :tangle parent.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000028
  algo:
    RSA:
      bits: 2048
  capabilities:
    - decrypt
    - restrict
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f parent.yml
#+END_SRC

Then, we can create non-persistent key:

#+BEGIN_SRC yaml :tangle child.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      parent: 0x81000028
  algo:
    RSA:
      bits: 2048
  capabilities:
    - sign
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f child.yml | tee child-full.yml
#+END_SRC

Inspecting ~child-full.yml~ reveals that the ~tpm~ section has been
extended with two new properties: ~private~ and ~unique~. This is the
private key wrapped (encrypted) using the parent key:

#+BEGIN_SRC yaml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      parent: 0x81000028
      private: 002035531cd18d59c7e358b63b1f89ed3b2fdd12176ed5c02f5d68dfbf7f872c65ae00107170ee9bc217b4a7ed59ad11a1387aef195031690b01d6d3acd6b4f63d16006bb33737392dd1ba9753bcf81227e3dffecddc082821994e41c047e325d82ee2c3106e94d5f5bbcd935e6f80e2321f24012a24be73f231c9f6606d927016b3afd73b96df2e3f5a181cfbe436da9cf9bcefa1a1513cb63e8021fb9ad2cc81bce55d9651aa7ed8aeaccba7ba98834d759e9f3b30e21953e65a12742bc253dfbef1e8e158fcc9755acd08e3f4af4183b7b008c4ec0865b48315d346be
      unique:
        RSA:
          bytes:  
    algo:
      RSA:
        bits: 2048
    capabilities:
      - sign
    auth: 123
#+END_SRC

Except for the different configuration this key is perfectly usable in
all operations:

#+BEGIN_SRC sh
get-key -f child-full.yml
#+END_SRC

#+RESULTS:
: public_key:
:   RSA:
:     bytes:  
: manu: 1398033696
: name: 000bc287d88098837a6fa7732ac5f1735996a4b5e7827fb0e82177b763b31654c77c

*** EC: NIST-P256

Keys need to be wrapped using a key parent that itself needs to be
persistent:

#+BEGIN_SRC yaml :tangle parent-nist-p256.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000328
  algo:
    EC:
      curve: NIST-P256
  capabilities:
    - decrypt
    - restrict
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f parent-nist-p256.yml
#+END_SRC

Then, we can create non-persistent key:

#+BEGIN_SRC yaml :tangle child-nist-p256.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      parent: 0x81000328
  algo:
    EC:
      curve: NIST-P256
  capabilities:
    - sign
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f child-nist-p256.yml | tee child-nist-p256-complete.yml
#+END_SRC

Inspecting ~child-nist-p256-complete.yml~ reveals that the ~tpm~ section
has been extended with two new properties: ~private~ and ~unique~. This is
the private key wrapped (encrypted) using the parent key:

#+BEGIN_SRC yaml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      parent: 0x81000328
      private: 0020f02ddfa535dfae96031629c001868c0c28358df4d8d8784536a22faa7fea90020010a27a2d5a839d5bece4c50110e189dbf67d76f6f7f68a71301791fe0db8c187b1495621d1b4776fdc2f8b184451d16fd1aacc8261005df7c86058a7fa1609dce2e5a8ec7c631398b2e57e288dbe99059de30cfabdbcd057c53763
      unique:
        EC:
          x: 1f93e6eb830bfb22b6ac482f3c41770a65ab6478c5c0c4d0758b250289defc0b
          y: c211a231b6d5313a8a78af4a621ce7766ca1c000c59e904ed3f1fa38ff54cb72
  algo:
    EC:
      curve: NIST-P256
  capabilities:
    - sign
  auth: 123
#+END_SRC

Except for the different configuration this key is perfectly usable in
all operations:

#+BEGIN_SRC sh
get-key -f child-nist-p256-complete.yml
#+END_SRC

#+RESULTS:
: public_key:
:   EC:
:     x: 1f93e6eb830bfb22b6ac482f3c41770a65ab6478c5c0c4d0758b250289defc0b
:     y: c211a231b6d5313a8a78af4a621ce7766ca1c000c59e904ed3f1fa38ff54cb72
: manu: 1398033696
: name: 000b1a7ea2e65a4c70d21c2af706ed370b20a56b28f644d19b7501345910a3a3e7cd

*** EC: NIST-P384

Keys need to be wrapped using a key parent that itself needs to be
persistent:

#+BEGIN_SRC yaml :tangle parent-nist-p384.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000428
  algo:
    EC:
      curve: NIST-P384
  capabilities:
    - decrypt
    - restrict
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f parent-nist-p384.yml
#+END_SRC

Then, we can create non-persistent key:

#+BEGIN_SRC yaml :tangle child-nist-p384.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      parent: 0x81000428
  algo:
    EC:
      curve: NIST-P384
  capabilities:
    - sign
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f child-nist-p384.yml | tee child-nist-p384-complete.yml
#+END_SRC

Inspecting ~child-nist-p384-complete.yml~ reveals that the ~tpm~ section
has been extended with two new properties: ~private~ and ~unique~. This is
the private key wrapped (encrypted) using the parent key:

#+BEGIN_SRC yaml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      parent: 0x81000428
      private: 0020fb1df208021cab7898d4edba2e87966a62e4e95820ad695b8d5af40351361f9100102e21b1075be238d84a9b98471879ec2cc415b4b0309edf82dd6b5a00fa557b9dc06ea752ea36fb4dea4f9a47c5884e1d43e0fcbd40db477e4147264f202145e1c995f411406c82d444a91d67edf69c824737e32057728d9f04193b469b3759bbb033673fafec5db9fa86
      unique:
        EC:
          x: cf159a49527490e60ba5cede361ca82a43d41e6754e8ddea1f57fdba9e05bd49ed62bb982994407801f95c366f85ef43
          y: 322ee52ffde0fe5f85367f801a0cbc5f05a772e6ac86027eed64a02303683b2caa1adb0674645533cb578284ee86eaab
  algo:
    EC:
      curve: NIST-P384
  capabilities:
    - sign
  auth: 123
#+END_SRC

Except for the different configuration this key is perfectly usable in
all operations:

#+BEGIN_SRC sh
get-key -f child-nist-p384-complete.yml
#+END_SRC

#+RESULTS:
: public_key:
:   EC:
:     x: cf159a49527490e60ba5cede361ca82a43d41e6754e8ddea1f57fdba9e05bd49ed62bb982994407801f95c366f85ef43
:     y: 322ee52ffde0fe5f85367f801a0cbc5f05a772e6ac86027eed64a02303683b2caa1adb0674645533cb578284ee86eaab
: manu: 1398033696
: name: 000b1a7ea2e65a4c70d21c2af706ed370b20a56b28f644d19b7501345910a3a3e7cd

** Importing private keys

It is also possible to import already existing private keys into the TPM.

*** RSA

#+BEGIN_SRC yaml :tangle private-key.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
  algo:
    RSA:
      bits: 1024
  private:
    rsa:
      prime: f69495352f2ab58db89a0a6ddb060ca0baa5ec190d1d61f0fae32cdfb7516fc9e4968b5c494c057f35dfe69136fe35434f0a3b8979551347c47a357abad0ad0b
      modulus:
        bytes: cd1abae5d734341ad373bae4f9ef46b1cf699d4054c859b9c0f0c811ca4d7b1cb03c66ea655156639b78c5db2c2fea42430f417ab3d4aee5f63b881dd106a3c60105bc46bb18c7a794a17f50392405551f77287e61b5f784354cd351021e1853b0cfd3470d4cc9bd9e39836b83c1be6bb200fef56786406e8cd45f73e4a9f523
      exponent: 65537
  capabilities:
    - sign
  auth: 123
#+END_SRC

Using these keys is the same as for any other type of key:

#+BEGIN_SRC sh :results verbatim
get-key -f private-key.yml
#+END_SRC

#+RESULTS:
: ---
: public_key:
:   RSA:
:     bytes: cd1abae5d734341ad373bae4f9ef46b1cf699d4054c859b9c0f0c811ca4d7b1cb03c66ea655156639b78c5db2c2fea42430f417ab3d4aee5f63b881dd106a3c60105bc46bb18c7a794a17f50392405551f77287e61b5f784354cd351021e1853b0cfd3470d4cc9bd9e39836b83c1be6bb200fef56786406e8cd45f73e4a9f523
: manu: 1398033696
: name: 000bb0369f40552df81f3bda82053e1974ffb5e2ca32999c602ee67428703e8211ad
: 

*** EC: NIST-P256

To generate a new P-256 key use the following openssl command:

#+BEGIN_SRC sh :results verbatim
openssl ecparam -name secp256r1 -genkey -noout | openssl ec -in - -inform engine -text -noout -conv_form uncompressed
#+END_SRC

#+RESULTS:
#+begin_example
Private-Key: (256 bit)
priv:
    98:20:9e:ea:87:b0:63:ec:a8:51:09:ef:1b:8a:46:
    c0:97:ab:25:2c:59:fb:a1:2f:38:99:e3:8f:e5:4e:
    d4:1b
pub:
    04:12:b2:a3:f6:de:b2:74:df:7d:fa:6a:9e:6e:13:
    de:a9:b9:51:5d:59:0a:66:69:66:de:fe:f5:f8:6d:
    1e:ca:df:47:95:cf:10:a8:94:22:6f:17:78:dc:d4:
    18:5d:b5:c4:d4:2a:9c:10:59:1a:22:11:81:2e:f5:
    b6:54:09:4f:81
ASN1 OID: prime256v1
NIST CURVE: P-256
#+end_example

The =ec.parameter= value should reflect the =priv= field with all
bytes concatenated. The public part: =ec.points= would be two halves
of the =pub= openssl value (omitting first =04= byte).

#+BEGIN_SRC yaml :tangle private-key-nist-p256.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
  algo:
    EC:
      curve: NIST-P256
  private:
    ec:
      parameter: 98209eea87b063eca85109ef1b8a46c097ab252c59fba12f3899e38fe54ed41b
      points:
        x: 12b2a3f6deb274df7dfa6a9e6e13dea9b9515d590a666966defef5f86d1ecadf
        y: 4795cf10a894226f1778dcd4185db5c4d42a9c10591a2211812ef5b654094f81
  capabilities:
    - sign
  auth: 123
#+END_SRC

Using these keys is the same as for any other type of key:

#+BEGIN_SRC sh
get-key -f private-key-nist-p256.yml
#+END_SRC

#+RESULTS:
: public_key:
:   EC:
:     x: 12b2a3f6deb274df7dfa6a9e6e13dea9b9515d590a666966defef5f86d1ecadf
:     y: 4795cf10a894226f1778dcd4185db5c4d42a9c10591a2211812ef5b654094f81
: manu: 1229081888
: name: 000b23684f8b125caad589545052d8779253a6ef854f9290f7c8b670cb2c4165aa18

*** EC: NIST-P384

To generate a new P-384 key use the following openssl command:

#+BEGIN_SRC sh :results verbatim
openssl ecparam -name secp384r1 -genkey -noout | openssl ec -in - -inform engine -text -noout -conv_form uncompressed
#+END_SRC

#+RESULTS:
#+begin_example
Private-Key: (384 bit)
priv:
    a1:79:12:49:9c:40:12:98:ed:ec:db:89:f7:a3:08:
    75:74:6f:0e:fc:44:3e:be:d1:3a:05:3f:1a:2f:c6:
    45:97:3d:d3:5a:93:27:1c:6d:7f:25:79:36:95:bd:
    1c:4f:be
pub:
    04:e1:d7:38:d7:54:2b:83:b2:e8:bd:4d:cd:03:6f:
    f8:1c:a2:ed:08:30:1c:26:34:d2:c4:24:6c:3e:79:
    ae:e9:90:36:7c:f7:3b:c2:2c:29:50:da:e9:98:d7:
    97:a3:95:75:5e:cc:c5:61:a0:38:fd:76:ce:60:2a:
    7a:6c:0e:f4:51:db:3f:75:21:ac:ab:96:50:f7:77:
    09:b5:32:69:2d:93:23:98:e2:aa:09:ae:18:e4:20:
    db:16:56:57:12:c3:6f
ASN1 OID: secp384r1
NIST CURVE: P-384
#+end_example

The =ec.parameter= value should reflect the =priv= field with all
bytes concatenated. The public part: =ec.points= would be two halves
of the =pub= openssl value (omitting first =04= byte).

#+BEGIN_SRC yaml :tangle private-key-nist-p384.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
  algo:
    EC:
      curve: NIST-P384
  private:
    ec:
      parameter: 595e7774730018cc3942e4b713c2a288b8dbcec147ede1ed3c3760553bc39a7a092db968df4da71267c9586e69e6ffc7
      points:
        x: 88eae33668dfc22f1bec8ca87bef7dab67562b1b1bf10101b5a655212b31356d46963624e11f0b30ffb7bc60f315fb09
        y: 5c1ec2296140c2404a605e6c65b85c10d3e5807feb4d15f674e4318c7887e03408e98a348c413b16ad615484ed84cf2f
  capabilities:
    - sign
  auth: 123
#+END_SRC

Using these keys is the same as for any other type of key:

#+BEGIN_SRC sh
get-key -f private-key-nist-p384.yml
#+END_SRC

#+RESULTS:
: public_key:
:   EC:
:     x: 88eae33668dfc22f1bec8ca87bef7dab67562b1b1bf10101b5a655212b31356d46963624e11f0b30ffb7bc60f315fb09
:     y: 5c1ec2296140c2404a605e6c65b85c10d3e5807feb4d15f674e4318c7887e03408e98a348c413b16ad615484ed84cf2f
: manu: 1398033696
: name: 000b4c2c9cf06ff4af433703b1459bf1529311fcc7a24c6e407594ba071a7bc82060

** Signing digests

*** RSA

Signing uses raw RSA keys and produces raw PKCS1.5 signatures for now.

Ultimately these raw objects can be wrapped with protocol-specific
structures e.g. certificates (for raw RSA keys) or OpenPGP signatures
(for raw signatures).

Signing can use any key that has been defined previously:

#+BEGIN_SRC sh :results output
echo -n foo | openssl dgst -binary -sha256 | sign-digest -f key.yml | xxd
#+END_SRC

#+RESULTS:
#+begin_example
00000000: a2a7 066e 813b 0ae9 a978 2f78 dbb1 c25d  ...n.;...x/x...]
00000010: 3402 fca2 106e 4052 ef3f e370 399d e95f  4....n@R.?.p9.._
00000020: 45d3 5f56 f915 5f81 c9e9 6b4b ff27 9529  E._V.._...kK.'.)
00000030: 591c 0cf2 6a19 18d5 af6a e2e1 161b b950  Y...j....j.....P
00000040: cbfe 715b 201c e1dc 6691 f862 9e1b ca87  ..q[ ...f..b....
00000050: 2313 f774 f689 dd5b e28f 9c9b 275c 6432  #..t...[....'\d2
00000060: e491 533a 5509 bd9b 5ddf 8403 81cb e341  ..S:U...]......A
00000070: 2fc7 23e9 9c93 4170 48e7 cdda 3c07 0151  /.#...ApH...<..Q
00000080: dafd 00bb 352e dacc 33a9 a087 9a9d 93cf  ....5...3.......
00000090: 4dff d59d 7f19 ca68 3d6e e3e7 26f5 17d4  M......h=n..&...
000000a0: c683 677e c039 dd4e 27ff f2db f354 9fe1  ..g~.9.N'....T..
000000b0: 6e7a 1ea5 c215 ba4d 44c1 5f72 0bce 1fe9  nz.....MD._r....
000000c0: 53c2 3cbf 8412 d610 784d 6cf5 aa56 2c87  S.<.....xMl..V,.
000000d0: 48a2 dbdf 3944 9ae3 94ae 2a57 98bb 420c  H...9D....*W..B.
000000e0: 842e 2aa6 7dd2 1842 7ef4 5208 3b47 d410  ..*.}..B~.R.;G..
000000f0: 137f 9292 8d94 d5e3 64c0 2a2b e4e8 4342  ........d.*+..CB
#+end_example

*** EC: NIST-P256

Signing uses raw elliptic curve keys and produces a concatenation of R
and S values.

Ultimately these raw objects can be wrapped with protocol-specific
structures e.g. certificates (for raw RSA keys) or OpenPGP signatures
(for raw signatures).

Signing can use any key that has been defined previously:

#+BEGIN_SRC sh :results output
echo -n foo | openssl dgst -binary -sha256 | sign-digest -f key-nist-p256.yml | xxd
#+END_SRC

#+RESULTS:
: 00000000: 2b10 9aca a8ec 800c 4b50 b35a a62e 6f52  +.......KP.Z..oR
: 00000010: 5bc3 a3c9 5c68 bd2a 4588 b7e8 94f6 2923  [...\h.*E.....)#
: 00000020: f3e4 b073 82a1 42b4 1139 e5d0 d7a3 996d  ...s..B..9.....m
: 00000030: 8893 a60a 6171 ddc1 ecb6 2992 8382 d8d2  ....aq....).....

*** EC: NIST-P384

Signing uses raw elliptic curve keys and produces a concatenation of R
and S values.

Ultimately these raw objects can be wrapped with protocol-specific
structures e.g. certificates (for raw RSA keys) or OpenPGP signatures
(for raw signatures).

Signing can use any key that has been defined previously:

#+BEGIN_SRC sh :results output
echo -n foo | openssl dgst -binary -sha256 | sign-digest -f key-nist-p384.yml | xxd
#+END_SRC

#+RESULTS:
: 00000000: a33b 5ed4 bbbc f6bd 6297 c696 fc10 5ae4  .;^.....b.....Z.
: 00000010: 4a32 d807 a065 ea75 19b9 7d2f 9f05 8e09  J2...e.u..}/....
: 00000020: a6b6 028b 2eb7 9c7f ab6e 8701 61a3 e39d  .........n..a...
: 00000030: 23db fc1b b859 e2dd 20e5 ebc9 3503 c671  #....Y.. ...5..q
: 00000040: 00e2 057c 3b00 86fa 84e8 4152 3b9d 9e70  ...|;.....AR;..p
: 00000050: 5a19 05a0 f13f 64f6 ddd7 5edd 764c 6cea  Z....?d...^.vLl.

** Decryption

*** RSA

Encryption and decryption works similarily to signing. The plaintext
is being passed as standard input to =encrypt-raw= commmand and it
outputs the raw cipher text. =decrypt-raw= works in the other direction
consuming the cipher text and producing the plain text.

Both of these take the key defintion as a sole argument.

#+BEGIN_SRC sh :results output
echo this is a sample encryption message | encrypt-raw -f decryption.yml > encrypted
decrypt-raw -f decryption.yml < encrypted
#+END_SRC

#+RESULTS:
: this is a sample encryption message

*** ECDH

Encryption and decryption with EC keys works a little bit
differently. EC key is used to generate two points: one is a public
point that will be shared with the other party, the other is used as a
symmetric key for encryption of the actual data.

First, we need an EC key with =decrypt= capability. The key cannot be
marked as =restrict= as that will prevent decryption.

#+BEGIN_SRC yaml :tangle key-nist-p256-decryption.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000147
  algo:
    EC:
      curve: NIST-P256
  capabilities:
    - decrypt
  auth: 123
#+END_SRC

Then we generate two points: public point and the shared secret:

#+BEGIN_SRC sh
create-key -f key-nist-p256-decryption.yml

# create a shared secret and public point
ecdh-key-gen -f key-nist-p256-decryption.yml --public-point public.bin > shared-secret.bin

echo "Public point:"
xxd public.bin

echo "Shared secret:"
xxd shared-secret.bin
#+END_SRC

And we use the shared secret to encrypt the message. Shared secret is
removed as it is no longer necessary. The public point, along with the
encrypted message, is transferred.

#+BEGIN_SRC sh
# encrypt the message using shared secret
echo this is a sample encryption message | openssl aes-256-cbc -e -kfile shared-secret.bin > encrypted

# remove shared secret, move public point and encrypted message to the other party
rm shared-secret.bin
#+END_SRC

The decrypting party first recovers the shared secret using the public
point. Then the shared secret is passed to symmetric algorithm as a
key (here using OpenSSL):

#+BEGIN_SRC sh
# recover shared secret using private key and the public point
ecdh-recover -f key-nist-p256-decryption.yml --public-point public.bin > shared-secret.bin

# decrypt the message
openssl aes-256-cbc -d -kfile shared-secret.bin -in encrypted
#+END_SRC

#+RESULTS:
: this is a sample encryption message

This concludes our basic TPM usage section. TPM will be cleared discarding all keys:

#+BEGIN_SRC sh
tpm2_clear
#+END_SRC

* Key duplication

Key duplication allows secure private key material transfer from one
machine (e.g. offline computer) to the other (e.g. online computer).

The main benefit is that the online computer never sees private key
bits in plain. They are encrypted to the storage key that is stored in
the TPM chip. The encrypted private key is decrypted by the TPM during
import.

On online laptop, export the TPM key that will serve as parent for the
imported key. This parent key needs to have =decrypt= and =restrict=
capabilities.

#+BEGIN_SRC yaml :tangle duplication-parent.yml
spec:
  provider:
    tpm:
      tcti: "mssim:"
      handle: 0x81000027
  algo:
    RSA:
      bits: 2048
  capabilities:
    - decrypt
    - restrict
  auth: 123
#+END_SRC

#+BEGIN_SRC sh
create-key -f duplication-parent.yml
#+END_SRC

Retrieve the key's public key bits and transfer them to the offline computer:

#+BEGIN_SRC sh
get-key -f duplication-parent.yml | tee duplication-parent-full.yml
#+END_SRC

#+RESULTS:
#+begin_example
spec:
  provider:
    tpm:
      tcti: "device:/dev/tpmrm0"
      handle: 2164260888
      parent: ~
      private: ~
      unique:
        RSA:
          bytes:  
  algo:
    RSA:
      bits: 2048
      exponent: ~
  private: ~
  capabilities:
    - decrypt
    - restrict
  auth: "123"
#+end_example

Now, taking the private key and wrapping it with the parent's key:

#+BEGIN_SRC sh
wrap --parent duplication-parent-full.yml  -f private-key.yml | tee key-to-import.yml
#+END_SRC

#+RESULTS:
#+begin_example
spec:
  provider:
    tpm:
      tcti: "mssim:"
      parent: 2164260903
      unique:
        RSA:
          bytes: cd1abae5d734341ad373bae4f9ef46b1cf699d4054c859b9c0f0c811ca4d7b1cb03c66ea655156639b78c5db2c2fea42430f417ab3d4aee5f63b881dd106a3c60105bc46bb18c7a794a17f50392405551f77287e61b5f784354cd351021e1853b0cfd3470d4cc9bd9e39836b83c1be6bb200fef56786406e8cd45f73e4a9f523
      wrapped:
        secret:  
        private: 0020dccc065f0fc4c8db35c0a26f7742df8efa0fa7dfe7964d6e5f004405aa1fff280abec442094816fc2b51f58ea277ab49b61db7ca007f4387f251a8f1db2af77cf7fdd6ded9d793d91891c9cd7e47e18bffc3b2280bbd0e3a5b8685cfe934a199d57db474592194cd29f5701f8042318062685103e987caa88b7e8ba5cc741c576f37b4d545d0d3ed2fa2
        data: ""
      policy: 09bd2ec618ec5d4688b2861cd8aedbbce1c1dd0b9e31e4a12f837750b33831e2
  algo:
    RSA:
      bits: 1024
  capabilities:
    - sign
  auth: "123"
#+end_example

The duplicated key can then be imported:

#+BEGIN_SRC sh
create-key -f key-to-import.yml | tee duplicated-key.yml
#+END_SRC

#+RESULTS:
#+begin_example
spec:
  provider:
    tpm:
      tcti: "mssim:"
      parent: 2164260903
      private: 00202a2ee14685008e505bf6284cd2250f4071d6cfa06e344d5e1462acb8cad0cdba0010058b8588770859c9271d31729a56b3f4d9d2b01e45e9209cbeecb7b95aa7ff86edbc8ca350abcbd28391bea433ec9eb82e8490821669d34d2362b4558c034305b5c8d51417751efad8d414e0df781785e56f8bab9395655d0a753fdf17efe0f4e6df85b8958e9df7bb29371ab22cd49e82bd1da05d4e15d971ae
      unique:
        RSA:
          bytes: cd1abae5d734341ad373bae4f9ef46b1cf699d4054c859b9c0f0c811ca4d7b1cb03c66ea655156639b78c5db2c2fea42430f417ab3d4aee5f63b881dd106a3c60105bc46bb18c7a794a17f50392405551f77287e61b5f784354cd351021e1853b0cfd3470d4cc9bd9e39836b83c1be6bb200fef56786406e8cd45f73e4a9f523
      policy: 09bd2ec618ec5d4688b2861cd8aedbbce1c1dd0b9e31e4a12f837750b33831e2
  algo:
    RSA:
      bits: 1024
  capabilities:
    - sign
  auth: "123"
#+end_example

Note that the imported key has =wrapped= key set. Import procedure
checks the integrity of the key and if the encrypted seed can be
successfully imported the =wrapped= key is removed and a regular
=private= value is being inserted.

The duplicated key can be inspected for public key:

#+BEGIN_SRC sh
get-key -f duplicated-key.yml
#+END_SRC

It also works the same way as any other key:

#+BEGIN_SRC sh
echo -n foo | openssl dgst -binary -sha256 | sign-digest -f duplicated-key.yml | xxd
#+END_SRC

#+RESULTS:
#+begin_example
00000000: ba01 7074 b3b4 07bd 9ea5 28fb a04f 1f83  ..pt......(..O..
00000010: 8fa5 6965 e2de 71cb d320 4332 60a9 f088  ..ie..q.. C2`...
00000020: 7725 5145 5688 9a12 97fa 5ad8 7c6f 3213  w%QEV.....Z.|o2.
00000030: d21d 4c84 4888 e3f6 4eab 988c 5b72 eb65  ..L.H...N...[r.e
00000040: d88b 16b3 473b 91d8 053e 05de 5733 208e  ....G;...>..W3 .
00000050: e8ad 6a3e 22eb 349d 1798 ef0e 8924 2f35  ..j>".4......$/5
00000060: 2dce 3af5 e1d3 47b9 cb9e 9ccd bc63 7e91  -.:...G......c~.
00000070: 23e6 cac0 83e9 10a8 0aaa 7a06 6579 87ee  #.........z.ey..
#+end_example

* Work plan

Work on this project is being sponsored by NLnet. See
https://nlnet.nl/project/Sequoia-TPM/ for details.

** Signing and decryption using RSA keys [5/5]
  - [X] Creating new RSA keys and persisting them in TPM memory
  - [X] Using non-persistent RSA keys (that don't use up TPM memory)
  - [X] Importing RSA private keys to TPM (for already existing keys)
  - [X] Signing using RSA keys in the TPM
  - [X] Decryption using RSA keys in the TPM

** Support for Elliptic Curve algorithms [5/5]
  - [X] Creating new EC keys and persisting them in TPM memory
  - [X] Using non-persistent EC keys (that don't use up TPM memory)
  - [X] Importing EC private keys to TPM (for already existing keys)
  - [X] Signing using EC keys in the TPM
  - [X] Decryption using EC keys in the TPM

** Key migration support [4/4]
  - [X] Export of TPM encryption key
  - [X] Wrapping user's private key using TPM encryption key
  - [X] Import of the wrapper private key to the TPM chip
  - [X] PR to the upstream rust-tss-esapi crate

** Design and implementation of private key store crate [/]
  - [ ] Implementation of Sequoia's Decryptor and Signer traits for TPM keys
  - [ ] API for managing TPM keys
  - [ ] API for key migration

** Test harness using a TPM simulator [/]
  - [ ] Integration tests for creating, importing keys
  - [ ] Test cases for encryption (using Sequoia) and decryption (using TPM crate)
  - [ ] Tests for key migration

** Extending Sequoia's CLI to support private key store [/]
  - [ ] Extension to the CLI to allow specifying the location of the private key store
  - [ ] Modification to the sourec code not to rely on software private keys

** Documentation for tools and the API [/]
  - [ ] Making sure all functions and items are documented
  - [ ] Including README and end-user documentation on how to use the project
  - [ ] Adding best practices document
