Repository: scionproto/scion
Pull request #4615 (2024-09-11 17:26:37)

doc: rewrite TRC ceremony documentation to include scion-pki
Rewrite the TRC ceremony documentation to include the scion-pki tool which is a lot more ergonomic than openssl based approach. The openssl based approach is still kept such that people do not need to trust the distributed scion-pki tool.

Furthermore, the documentation and tests are updated to use openssl 3.0.14.

And finally, the scion-pki tool is extended to support RFC3339 based timestamps when creating TRC payloads for both NotBefore and NotAfter fields. The legacy unix timestamp and duration based validity time are still supported.

jiceatscion: 

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/scionproto/scion/4615)
<!-- Reviewable:end -->


Patch:
diff --git a/Makefile b/Makefile
index d82db1af8..25e994ea5 100644
--- a/Makefile
+++ b/Makefile
@@ -86,6 +86,7 @@ mocks:
 
 gazelle: go_deps.bzl
 	bazel run //:gazelle --verbose_failures --config=quiet
+	./tools/buildrill/go_integration_test_sync
 
 licenses:
 	tools/licenses.sh
diff --git a/doc/command/scion-pki/scion-pki_trc.rst b/doc/command/scion-pki/scion-pki_trc.rst
index 1fe83166b..8ce820ac6 100644
--- a/doc/command/scion-pki/scion-pki_trc.rst
+++ b/doc/command/scion-pki/scion-pki_trc.rst
@@ -27,7 +27,7 @@ SEE ALSO
 * :ref:`scion-pki trc combine <scion-pki_trc_combine>` 	 - Combine partially signed TRCs
 * :ref:`scion-pki trc extract <scion-pki_trc_extract>` 	 - Extract parts of a signed TRC
 * :ref:`scion-pki trc format <scion-pki_trc_format>` 	 - Reformat a TRC or TRC payload
-* :ref:`scion-pki trc inspect <scion-pki_trc_inspect>` 	 - Represent TRC in a human readable form
+* :ref:`scion-pki trc inspect <scion-pki_trc_inspect>` 	 - Print TRC details in a human readable format
 * :ref:`scion-pki trc payload <scion-pki_trc_payload>` 	 - Generate new TRC payload
 * :ref:`scion-pki trc sign <scion-pki_trc_sign>` 	 - Sign a TRC
 * :ref:`scion-pki trc verify <scion-pki_trc_verify>` 	 - Verify a TRC chain
diff --git a/doc/command/scion-pki/scion-pki_trc_inspect.rst b/doc/command/scion-pki/scion-pki_trc_inspect.rst
index 39ffbd38d..0caa37ea1 100644
--- a/doc/command/scion-pki/scion-pki_trc_inspect.rst
+++ b/doc/command/scion-pki/scion-pki_trc_inspect.rst
@@ -5,13 +5,13 @@
 scion-pki trc inspect
 ---------------------
 
-Represent TRC in a human readable form
+Print TRC details in a human readable format
 
 Synopsis
 ~~~~~~~~
 
 
-'human' outputs the TRC contents in a human readable form.
+'inspect' prints the details of a TRC a human-readable fromat.
 
 The input file can either be a TRC payload, or a signed TRC.
 The output can either be in yaml, or json.
@@ -29,8 +29,8 @@ Examples
 
 ::
 
-    scion-pki trc human ISD1-B1-S1.pld.der
-    scion-pki trc human ISD1-B1-S1.trc
+    scion-pki trc inspect ISD1-B1-S1.pld.der
+    scion-pki trc inspect ISD1-B1-S1.trc
 
 Options
 ~~~~~~~
diff --git a/doc/conf.py b/doc/conf.py
index e41f7b1b4..9f26c8ac5 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -7,9 +7,9 @@ import subprocess
 
 # -- Project information -----------------------------------------------------
 
-project = 'SCION'
-copyright = '2023, Anapaya Systems, ETH Zurich, SCION Association'
-author = 'Anapaya Systems, ETH Zurich, SCION Association'
+project = "SCION"
+copyright = "2023, Anapaya Systems, ETH Zurich, SCION Association"
+author = "Anapaya Systems, ETH Zurich, SCION Association"
 
 
 # -- General configuration ---------------------------------------------------
@@ -18,32 +18,37 @@ author = 'Anapaya Systems, ETH Zurich, SCION Association'
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 extensions = [
-    'recommonmark',
-    'sphinx_rtd_theme',
-    'sphinx.ext.extlinks',
-    'sphinxcontrib.openapi',
-    'sphinx_copybutton',
+    "recommonmark",
+    "sphinx_copybutton",
+    "sphinx_design",
+    "sphinx_rtd_theme",
+    "sphinx.ext.extlinks",
+    "sphinxcontrib.openapi",
 ]
 
-copybutton_prompt_text = r'\w*\$ '  # matches e.g. <hostname>$
+copybutton_prompt_text = r"\w*\$ "  # matches e.g. <hostname>$
 copybutton_prompt_is_regexp = True
 copybutton_only_copy_prompt_lines = True
 
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This pattern also affects html_static_path and html_extra_path.
 exclude_patterns = [
-    'venv', 'requirements.in', 'requirements.txt',
-    '_build', 'Thumbs.db', '.DS_Store',
-    'manuals/*/*',  # manuals/<x>.rst uses "include" directive to compose files from subdirectories
-    'dev/design/TEMPLATE.rst',
+    "venv",
+    "requirements.in",
+    "requirements.txt",
+    "_build",
+    "Thumbs.db",
+    ".DS_Store",
+    "manuals/*/*",  # manuals/<x>.rst uses "include" directive to compose files from subdirectories
+    "dev/design/TEMPLATE.rst",
 ]
 
-master_doc = 'index'
+master_doc = "index"
 
 nitpicky = True
 
@@ -55,17 +60,19 @@ option_emphasise_placeholders = True
 # Note: somewhat obviously, these links will only work if the current rev has been pushed.
 try:
     file_ref_commit = subprocess.run(
-        ['git', 'rev-parse', "HEAD"],
-        capture_output=True, text=True, check=True
+        ["git", "rev-parse", "HEAD"], capture_output=True, text=True, check=True
     ).stdout.strip()
 except subprocess.CalledProcessError:
     file_ref_commit = "master"  # only used on unexpected problem with executing git
 
 extlinks = {
     # :issue:`123` is an issue link displayed as "#123"
-    'issue': ('https://github.com/scionproto/scion/issues/%s', '#%s'),
+    "issue": ("https://github.com/scionproto/scion/issues/%s", "#%s"),
     # :file-ref:`foo/bar.go` is a link to a file in the repo, displayed as "foo/bar.go"
-    'file-ref': ('https://github.com/scionproto/scion/blob/'+file_ref_commit+'/%s', '%s'),
+    "file-ref": (
+        "https://github.com/scionproto/scion/blob/" + file_ref_commit + "/%s",
+        "%s",
+    ),
 }
 
 # -- Options for HTML output -------------------------------------------------
@@ -73,7 +80,7 @@ extlinks = {
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_theme = 'sphinx_rtd_theme'
+html_theme = "sphinx_rtd_theme"
 
 html_theme_options = dict(
     style_external_links=True,
@@ -85,8 +92,8 @@ manpages_url = "https://manpages.debian.org/{path}"
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['']
+html_static_path = [""]
 
 html_css_files = [
-    'css/custom.css',
+    "css/custom.css",
 ]
diff --git a/doc/cryptography/ca-operations.rst b/doc/cryptography/ca-operations.rst
index 379b6a373..71d2c91d7 100644
--- a/doc/cryptography/ca-operations.rst
+++ b/doc/cryptography/ca-operations.rst
@@ -15,9 +15,16 @@ Certificates.
 The process of creating new CA Certificates is described in section `CA Certificates`_.
 The process of creating new AS Certificates is described in section `AS Certificates`_.
 
-To follow the steps in this document, ``openssl`` version ``1.1.1d`` or later is
+To follow the steps in this document, ``openssl`` version ``3.0.14`` or later is
 required.
 
+.. note::
+
+   The following document is meant as an example for easily running a manual CA
+   for testing purposes. In productive environments, these processes should be
+   automated and proper CA software should be used.
+
+
 .. _ca-cert:
 
 CA Certificates
@@ -32,42 +39,49 @@ itself.
 Creating the initial CA Certificate
 -----------------------------------
 
-The steps in creating a new CA Certificate are:
+.. tab-set::
+   :sync-group: tool
 
-#. Define the configuration of the CA Certificate in accordance with
-   :ref:`the SCION requirements <cp-ca-certificate>`.
-#. Create a new key pair.
-#. Create a Certificate Signing Request using the key pair.
-#. Use the Root Key and the Certificate Signing Request to create the new CA Certificate.
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-The configuration is defined in a file. OpenSSL reads the file and creates a
-certificate that is compatible with SCION. An example configuration file is
-included below. Note that the file includes the text ``{{.ShortOrg}}``; this
-text **must** be replaced with the shortname of your organization. For example,
-if your organization name is **ExampleCorp**, the line should contain ``name =
-ExampleCorp Secure CA Certificate``.
+      The steps in creating a new CA Certificate are:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE ca_conf START
-   :end-before: LITERALINCLUDE ca_conf END
+      #. Define the subject of the CA Certificate.
+      #. Create the certificate using the Root Key.
 
-.. attention::
+      The subject template has already been created in preparation for the TRC
+      ceremony. Here is a reminder how it looks like:
 
-   SCION CA certificates have short lifetimes (a lifetime of 11 days is recommended).
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE basic_conf_scion_pki START
+         :end-before: LITERALINCLUDE basic_conf_scion_pki END
 
-Once the file is ready, the rest of the steps can be executed through a series
-of ``openssl`` commands.
+   .. tab-item:: openssl
+      :sync: openssl
 
-These commands contain must be configured using the following values:
+      The steps in creating a new CA Certificate are:
 
-- CA Certificate validity start date. Prior to this date, the certificate is
-  not considered valid. To configure this, replace occurrences of ``$STARTDATE``
-  with the date in ``YYYYMMDDHHMMSSZ`` notation. For example, June 24th, 2020 UTC
-  at noon is formatted as ``20200624120000Z``.
-- CA Certificate validity end date. After this date, the certificate is no
-  longer valid. To configure this, replace occurrences of ``$ENDDATE`` with
-  the desired date. This uses the same notation as the ``$STARTDATE``.
-- Folder where the keys are contained. To configure this, replace ``$KEYDIR`` with the folder name.
+      #. Define the configuration of the CA Certificate in accordance with
+         :ref:`the SCION requirements <cp-ca-certificate>`.
+      #. Create a new key pair.
+      #. Create a Certificate Signing Request using the key pair.
+      #. Use the Root Key and the Certificate Signing Request to create the new CA Certificate.
+
+      The configuration is defined in a file. OpenSSL reads the file and creates a
+      certificate that is compatible with SCION. An example configuration file is
+      included below. Note that the file includes the text ``{{.ShortOrg}}``; this
+      text **must** be replaced with the shortname of your organization. For example,
+      if your organization name is **ExampleCorp**, the line should contain ``name =
+      ExampleCorp Secure CA Certificate``.
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE ca_conf START
+         :end-before: LITERALINCLUDE ca_conf END
+
+.. attention::
+
+   SCION CA certificates have short lifetimes (a lifetime of 11 days is recommended).
 
 .. note::
 
@@ -75,19 +89,51 @@ These commands contain must be configured using the following values:
    ``$KEYDIR`` folder, and have the names ``cp-ca.key`` and ``cp-root.key``. If this
    is not the case, the commands should be adjusted with the proper key locations.
 
-Finally, to create the CA certificate, run the commands below.
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE gen_ca START
-   :end-before: LITERALINCLUDE gen_ca END
-   :dedent: 4
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-After generating the certificate, check that the output is reasonable:
+      Once the file is ready, create the certificate using the ``scion-pki``
+      binary with the desired common name.
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_ca START
-   :end-before: LITERALINCLUDE check_ca END
-   :dedent: 4
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_ca_scion_pki START
+         :end-before: LITERALINCLUDE gen_ca_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      Once the file is ready, the rest of the steps can be executed through a series
+      of ``openssl`` commands.
+
+      These commands contain must be configured using the following values:
+
+      - CA Certificate validity start date. Prior to this date, the certificate is
+        not considered valid. To configure this, replace occurrences of ``$STARTDATE``
+        with the date in ``YYYYMMDDHHMMSSZ`` notation. For example, June 24th, 2020 UTC
+        at noon is formatted as ``20200624120000Z``.
+      - CA Certificate validity end date. After this date, the certificate is no
+        longer valid. To configure this, replace occurrences of ``$ENDDATE`` with
+        the desired date. This uses the same notation as the ``$STARTDATE``.
+      - Folder where the keys are contained. To configure this, replace ``$KEYDIR`` with the folder name.
+
+
+      Finally, to create the CA certificate, run the commands below.
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_ca START
+         :end-before: LITERALINCLUDE gen_ca END
+         :dedent: 4
+
+      After generating the certificate, check that the output is reasonable:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_ca START
+         :end-before: LITERALINCLUDE check_ca END
+         :dedent: 4
 
 The certificate can be validated with with the ``scion-pki`` binary:
 
@@ -151,69 +197,107 @@ The steps in creating a new AS Certificate are:
 #. The CA uses its CA Key and the Certificate Signing Request to create the new AS Certificate.
 #. (If the AS and CA are different entities) The CA sends the AS Certificate back to the AS.
 
-The configuration is defined in a file. OpenSSL reads the file and creates a
-certificate that is compatible with SCION. An example configuration file is
-included below. Note that the file includes the text ``{{.ShortOrg}}``; this
-text **must** be replaced with the shortname of your organization. For example,
-if your organization name is **ExampleCorp**, the line should contain ``name =
-ExampleCorp Secure CA Certificate``.
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE as_conf START
-   :end-before: LITERALINCLUDE as_conf END
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-.. attention::
+      The subject template needs to be adapted to the entity that is creating the certificate
+      signing request. For simplicity, we reuse the same template for both the CA and the AS.
+      Adapt your template according to your needs.
 
-   SCION AS certificates have short lifetimes (a lifetime of 3 days is recommended).
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_as_scion_pki_as_steps START
+         :end-before: LITERALINCLUDE gen_as_scion_pki_as_steps END
 
-To create the key pair and certificate signing request (CSR), the AS then runs
-the OpenSSL commands below. In these commands, replace ``$KEYDIR`` with the
-folder where private keys should be stored:
+   .. tab-item:: openssl
+      :sync: openssl
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE gen_as_as_steps START
-   :end-before: LITERALINCLUDE gen_as_as_steps END
-   :dedent: 4
+      The configuration is defined in a file. OpenSSL reads the file and creates a
+      certificate that is compatible with SCION. An example configuration file is
+      included below. Note that the file includes the text ``{{.ShortOrg}}``; this
+      text **must** be replaced with the shortname of your organization. For example,
+      if your organization name is **ExampleCorp**, the line should contain ``name =
+      ExampleCorp Secure CA Certificate``.
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE as_conf START
+         :end-before: LITERALINCLUDE as_conf END
+
+      .. attention::
+
+         SCION AS certificates have short lifetimes (a lifetime of 3 days is recommended).
+
+      To create the key pair and certificate signing request (CSR), the AS then runs
+      the OpenSSL commands below. In these commands, replace ``$KEYDIR`` with the
+      folder where private keys should be stored:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_as_as_steps START
+         :end-before: LITERALINCLUDE gen_as_as_steps END
+         :dedent: 4
 
 If the AS and CA are different entities, the certificate signing request can
 then be sent to a CA for signing.
 
 This step is performed by an entity that is a CA in the ISD. The CA creates
 the certificate using its private key and the certificate signing request
-received from the AS. The CA must also define the following:
-
-- CA Certificate validity start date. Prior to this date, the certificate is
-  not considered valid. To configure this, in the command below replace
-  occurrences of ``$STARTDATE`` with the date in ``YYYYMMDDHHMMSSZ`` notation.
-  For example, June 24th, 2020 UTC at noon is formatted as ``20200624120000Z``.
-- CA Certificate validity end date. After this date, the certificate is no
-  longer valid. To configure this, in the command below replace occurrences of
-  ``$ENDDATE`` with the desired date. This uses the same notation as the
-  ``$STARTDATE``.
-
-Additionally, the CA should set ``$KEYDIR`` to the folder in which the private
+received from the AS. The CA should set ``$KEYDIR`` to the folder in which the private
 key file (the file is called ``cp-ca.key``, in this example) is stored.
 
-To create the certificate, the CA runs:
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE gen_as_ca_steps START
-   :end-before: LITERALINCLUDE gen_as_ca_steps END
-   :dedent: 4
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-After generating the certificate, check that the output is reasonable:
+      The CA must also define the following:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_as START
-   :end-before: LITERALINCLUDE check_as END
-   :dedent: 4
+      - AS Certificate validity start date and end date in RFC3339 format.
 
-The certificate can be validated with with the ``scion-pki`` binary:
+      To create the certificate, the CA runs:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_as_type START
-   :end-before: LITERALINCLUDE check_as_type END
-   :dedent: 4
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_as_scion_pki_ca_steps START
+         :end-before: LITERALINCLUDE gen_as_scion_pki_ca_steps END
+         :dedent: 4
+
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      The CA must also define the following:
+
+      - AS Certificate validity start date. Prior to this date, the certificate is
+        not considered valid. To configure this, in the command below replace
+        occurrences of ``$STARTDATE`` with the date in ``YYYYMMDDHHMMSSZ`` notation.
+        For example, June 24th, 2020 UTC at noon is formatted as ``20200624120000Z``.
+      - AS Certificate validity end date. After this date, the certificate is no
+        longer valid. To configure this, in the command below replace occurrences of
+        ``$ENDDATE`` with the desired date. This uses the same notation as the
+        ``$STARTDATE``.
+
+      To create the certificate, the CA runs:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_as_ca_steps START
+         :end-before: LITERALINCLUDE gen_as_ca_steps END
+         :dedent: 4
+
+      After generating the certificate, check that the output is reasonable:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_as START
+         :end-before: LITERALINCLUDE check_as END
+         :dedent: 4
+
+      The certificate can be validated with with the ``scion-pki`` binary:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_as_type START
+         :end-before: LITERALINCLUDE check_as_type END
+         :dedent: 4
 
 If the AS and CA are different entities, the CA should then send the certificate
 back to the AS that request it.
diff --git a/doc/cryptography/trc-signing-ceremony-phases-base.rst b/doc/cryptography/trc-signing-ceremony-phases-base.rst
index 5537899ef..2fab6a5ea 100644
--- a/doc/cryptography/trc-signing-ceremony-phases-base.rst
+++ b/doc/cryptography/trc-signing-ceremony-phases-base.rst
@@ -65,21 +65,51 @@ contained on the drive.
 For each certificate, the *ceremony administrator* displays the validity period
 and checks that they cover the previously agreed upon TRC validity.
 
-.. literalinclude:: trc_ceremony.sh
-   :start-after: LITERALINCLUDE display_validity START
-   :end-before: LITERALINCLUDE display_validity END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE display_validity_scion-pki START
+         :end-before: LITERALINCLUDE display_validity_scion-pki END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE display_validity START
+         :end-before: LITERALINCLUDE display_validity END
 
 Further, checks that the signature algorithms are correct:
 
-.. literalinclude:: trc_ceremony.sh
-   :start-after: LITERALINCLUDE display_signature_algo START
-   :end-before: LITERALINCLUDE display_signature_algo END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE display_signature_algo_scion-pki START
+         :end-before: LITERALINCLUDE display_signature_algo_scion-pki END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE display_signature_algo START
+         :end-before: LITERALINCLUDE display_signature_algo END
 
 And finally, checks that the certificates are of valid type:
 
-.. literalinclude:: trc_ceremony.sh
-   :start-after: LITERALINCLUDE validate_certificate_type START
-   :end-before: LITERALINCLUDE validate_certificate_type END
+.. tab-set::
+
+   .. tab-item:: scion-pki
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE validate_certificate_type START
+         :end-before: LITERALINCLUDE validate_certificate_type END
 
 If the results of these checks are as expected, the *ceremony administrator*
 computes the SHA256 sum for each certificate:
@@ -123,10 +153,9 @@ update. The value will be used to fill in the ``{{.VotingQuorum}}`` variable
 below.
 
 Last, ask the *voting representatives* for the validity period of the new TRC.
-The value will be used to fill in the ``{{.NotBefore}}`` and ``{{.Validity}}``
-variable below. The ``{{.NotBefore}}`` variable is represented as a UNIX
-timestamp (seconds since Epoch January 1st, 1970 UTC, e.g. ``1593000000``
-equals June 24th, 2020 UTC at noon).
+The value will be used to fill in the ``{{.NotBefore}}`` and ``{{.NotAfter}}``
+variable below. The ``{{.NotBefore}}`` and ``{{.NotAfter}}`` variable are
+represented as a `RFC3339 <https://www.rfc-editor.org/rfc/rfc3339>`__ timestamp.
 
 To highlight variable types, we include some examples. The format must include
 the part after the ``=`` sign exactly as it is written (i.e., with the exact
@@ -138,6 +167,9 @@ same quoting, parentheses, etc.).
 
 .. note::
 
+   Previous versions of ``scion-pki`` used UNIX timestamps for ``NotBefore`` and
+   and a time duration string for ``Validity``.
+
    The UNIX timestamp can be displayed in human readable form using the ``date``
    command::
 
@@ -160,9 +192,15 @@ correct.
 
 Once the data has been verified, compute the DER encoding of the TRC data:
 
-.. literalinclude:: trc_ceremony.sh
-   :start-after: LITERALINCLUDE create_payload START
-   :end-before: LITERALINCLUDE create_payload END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE create_payload START
+         :end-before: LITERALINCLUDE create_payload END
 
 Compute the SHA256 sum of the TRC payload file using:
 
@@ -192,10 +230,24 @@ have cast their votes and copied the signatures onto the *USB flash drive*.
 As part of this phase, the *voting representatives* inspect the TRC payload.
 Display the TRC payload using:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE display_payload START
-   :end-before: LITERALINCLUDE display_payload END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_payload_scion_pki START
+         :end-before: LITERALINCLUDE display_payload_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_payload START
+         :end-before: LITERALINCLUDE display_payload END
+         :dedent: 4
 
 Walk the *voting representatives* through the output and describe the meaning
 and implications of each part.
@@ -221,20 +273,35 @@ should be available at the following locations on the *USB flash drive*:
 
 To assemble the final TRC in a file, run the following command:
 
-.. literalinclude:: trc_ceremony.sh
-   :start-after: LITERALINCLUDE combine_payload START
-   :end-before: LITERALINCLUDE combine_payload END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE combine_payload START
+         :end-before: LITERALINCLUDE combine_payload END
 
 To check that the resulting TRC is correct, run:
 
-.. literalinclude:: trc_ceremony.sh
-   :start-after: LITERALINCLUDE verify_payload START
-   :end-before: LITERALINCLUDE verify_payload END
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE verify_trc START
-   :end-before: LITERALINCLUDE verify_trc END
-   :dedent: 4
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE verify_payload START
+         :end-before: LITERALINCLUDE verify_payload END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE verify_trc START
+         :end-before: LITERALINCLUDE verify_trc END
+         :dedent: 4
 
 Copy the signed TRC to the *USB flash drive* in the root directory. Disconnect
 the *USB flash drive*.
@@ -255,10 +322,24 @@ confirm that verification has finished successfully. If any verification fails,
 Furthermore, the *voting representatives* inspect that all signatures are present.
 Display the signed TRC with this command:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE display_signatures START
-   :end-before: LITERALINCLUDE display_signatures END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_signatures_scion_pki START
+         :end-before: LITERALINCLUDE display_signatures_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_signatures START
+         :end-before: LITERALINCLUDE display_signatures END
+         :dedent: 4
 
 Walk the *voting representatives* through the output and describe the meaning
 and implications of each part.
@@ -298,7 +379,7 @@ put in the current working directory.
 .. important::
 
    It is required that the machine used to execute the commands has openssl
-   version 1.1.1d or higher installed.
+   version 3.0.14 or higher installed.
 
 Phase 1 - Exchange of Certificates
 ----------------------------------
@@ -406,17 +487,45 @@ one using the *regular voting certificate* and one using the *sensitive voting c
 
 Before signing, check that the TRC payload is sound:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE display_payload START
-   :end-before: LITERALINCLUDE display_payload END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_payload_scion_pki START
+         :end-before: LITERALINCLUDE display_payload_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_payload START
+         :end-before: LITERALINCLUDE display_payload END
+         :dedent: 4
 
 To compute the signatures, run:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE sign_payload START
-   :end-before: LITERALINCLUDE sign_payload END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE sign_payload_scion_pki START
+         :end-before: LITERALINCLUDE sign_payload_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE sign_payload START
+         :end-before: LITERALINCLUDE sign_payload END
+         :dedent: 4
 
 .. Warning::
 
@@ -425,10 +534,24 @@ To compute the signatures, run:
 
 To sanity check that the signatures were created correctly, run:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_signed_payload START
-   :end-before: LITERALINCLUDE check_signed_payload END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_signed_payload_scion_pki START
+         :end-before: LITERALINCLUDE check_signed_payload_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_signed_payload START
+         :end-before: LITERALINCLUDE check_signed_payload END
+         :dedent: 4
 
 
 Connect the *USB flash drive* to the *device*, and copy ``$TRCID.regular.trc`` and
@@ -459,25 +582,52 @@ If the sum differs, then **Phase 3** and **Phase 4** need to be repeated.
 Next, check that all the fields are consistent with earlier choices. To print the fields
 that are present in the TRC, run:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE verify_trc START
-   :end-before: LITERALINCLUDE verify_trc END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony.sh
+         :start-after: LITERALINCLUDE verify_payload START
+         :end-before: LITERALINCLUDE verify_payload END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE verify_trc START
+         :end-before: LITERALINCLUDE verify_trc END
+         :dedent: 4
+
+      .. note::
+
+         The ``-no_check_time`` flag is needed when the validity time of the TRC is in
+         the future.
 
 If there is a mismatch between any of the fields and the desired policy, then
 **Phase 3** and **Phase 4** need to be repeated.
 
-.. note::
+As a final check, run:
 
-   The ``-no_check_time`` flag is needed when the validity time of the TRC is in
-   the future.
+.. tab-set::
+   :sync-group: tool
 
-As a final check, run:
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE display_signatures START
-   :end-before: LITERALINCLUDE display_signatures END
-   :dedent: 4
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_signatures_scion_pki START
+         :end-before: LITERALINCLUDE display_signatures_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_signatures START
+         :end-before: LITERALINCLUDE display_signatures END
+         :dedent: 4
 
 and check that the signature information of each signature is present; there should
 be 2 signatures for each *voting representative*. If a signature is missing, then
diff --git a/doc/cryptography/trc-signing-ceremony-phases-sensitive.rst b/doc/cryptography/trc-signing-ceremony-phases-sensitive.rst
index e6232a24e..331d17e40 100644
--- a/doc/cryptography/trc-signing-ceremony-phases-sensitive.rst
+++ b/doc/cryptography/trc-signing-ceremony-phases-sensitive.rst
@@ -76,21 +76,51 @@ contained on the drive.
 For each certificate, the *ceremony administrator* displays the validity period
 and checks that they cover the previously agreed upon TRC validity.
 
-.. literalinclude:: trc_ceremony_sensitive.sh
-   :start-after: LITERALINCLUDE display_validity START
-   :end-before: LITERALINCLUDE display_validity END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE display_validity_scion-pki START
+         :end-before: LITERALINCLUDE display_validity_scion-pki END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE display_validity START
+         :end-before: LITERALINCLUDE display_validity END
 
 Further, checks that the signature algorithms are correct:
 
-.. literalinclude:: trc_ceremony_sensitive.sh
-   :start-after: LITERALINCLUDE display_signature_algo START
-   :end-before: LITERALINCLUDE display_signature_algo END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE display_signature_algo_scion-pki START
+         :end-before: LITERALINCLUDE display_signature_algo_scion-pki END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE display_signature_algo START
+         :end-before: LITERALINCLUDE display_signature_algo END
 
 And finally, checks that the certificates are of valid type:
 
-.. literalinclude:: trc_ceremony_sensitive.sh
-   :start-after: LITERALINCLUDE validate_certificate_type START
-   :end-before: LITERALINCLUDE validate_certificate_type END
+.. tab-set::
+
+   .. tab-item:: scion-pki
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE validate_certificate_type START
+         :end-before: LITERALINCLUDE validate_certificate_type END
 
 If the results of these checks are as expected, the *ceremony administrator*
 computes the SHA256 sum for each certificate:
@@ -148,11 +178,11 @@ certificates in the predecessor TRC. To find the indices, you can use the ``scio
 trcs human`` command.
 
 Last, ask the *voting representatives* for the validity period of the new TRC.
-The value will be used to fill in the ``{{.NotBefore}}`` and ``{{.Validity}}``
-variable below. The ``{{.NotBefore}}`` variable is represented as a UNIX
-timestamp (seconds since Epoch January 1st, 1970 UTC, e.g. ``1621857600``
-equals May 24th, 2021 UTC at noon). Ensure that the selected validity
-period overlaps with the one of the predecessor TRC.
+The value will be used to fill in the ``{{.NotBefore}}`` and ``{{.NotAfter}}``
+variable below. The ``{{.NotBefore}}`` and ``{{.NotAfter}}`` variable are
+represented as a `RFC3339 <https://www.rfc-editor.org/rfc/rfc3339>`__ timestamp.
+Ensure that the selected validity period overlaps with the one of the
+predecessor TRC.
 
 To highlight variable types, we include some examples. The format must include
 the part after the ``=`` sign exactly as it is written (i.e., with the exact
@@ -164,6 +194,9 @@ same quoting, parentheses, etc.).
 
 .. note::
 
+   Previous versions of ``scion-pki`` used UNIX timestamps for ``NotBefore`` and
+   and a time duration string for ``Validity``.
+
    The UNIX timestamp can be displayed in human readable form using the ``date``
    command::
 
@@ -186,9 +219,15 @@ correct.
 
 Once the data has been verified, compute the DER encoding of the TRC data:
 
-.. literalinclude:: trc_ceremony_sensitive.sh
-   :start-after: LITERALINCLUDE create_payload START
-   :end-before: LITERALINCLUDE create_payload END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE create_payload START
+         :end-before: LITERALINCLUDE create_payload END
 
 Compute the SHA256 sum of the TRC payload file using:
 
@@ -223,10 +262,24 @@ signatures onto the *USB flash drive*.
 As part of this phase, the *voting representatives* inspect the TRC payload.
 Display the TRC payload using:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE display_payload START
-   :end-before: LITERALINCLUDE display_payload END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_payload_scion_pki START
+         :end-before: LITERALINCLUDE display_payload_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_payload START
+         :end-before: LITERALINCLUDE display_payload END
+         :dedent: 4
 
 Walk the *voting representatives* through the output and describe the meaning
 and implications of each part.
@@ -259,15 +312,35 @@ at the following locations on the *USB flash drive*:
 
 To assemble the final TRC in a file, run the following command:
 
-.. literalinclude:: trc_ceremony_sensitive.sh
-   :start-after: LITERALINCLUDE combine_payload START
-   :end-before: LITERALINCLUDE combine_payload END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE combine_payload START
+         :end-before: LITERALINCLUDE combine_payload END
 
 To check that the resulting TRC is correct, run:
 
-.. literalinclude:: trc_ceremony_sensitive.sh
-   :start-after: LITERALINCLUDE verify_payload START
-   :end-before: LITERALINCLUDE verify_payload END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE verify_payload START
+         :end-before: LITERALINCLUDE verify_payload END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE verify_trc START
+         :end-before: LITERALINCLUDE verify_trc END
+         :dedent: 4
 
 Copy the signed TRC to the *USB flash drive* in the root directory. Disconnect
 the *USB flash drive*.
@@ -288,9 +361,15 @@ confirm that verification has finished successfully. If any verification fails,
 Furthermore, the *voting representatives* inspect that all signatures are present.
 Display the signed TRC with this command:
 
-.. literalinclude:: trc_ceremony_sensitive.sh
-   :start-after: LITERALINCLUDE trc_content START
-   :end-before: LITERALINCLUDE trc_content END
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE trc_content START
+         :end-before: LITERALINCLUDE trc_content END
 
 Walk the *voting representatives* through the output and describe the meaning
 and implications of each part.
@@ -339,7 +418,7 @@ put in the current working directory.
 .. important::
 
    It is required that the machine used to execute the commands has openssl
-   version 1.1.1d or higher installed.
+   version 3.0.14 or higher installed.
 
 Phase 1 - Exchange of Certificates
 ----------------------------------
@@ -449,24 +528,66 @@ one using the *regular voting certificate* and one using the *sensitive voting c
 
 Before signing, check that the TRC payload is sound:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE display_payload START
-   :end-before: LITERALINCLUDE display_payload END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_payload_scion_pki START
+         :end-before: LITERALINCLUDE display_payload_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE display_payload START
+         :end-before: LITERALINCLUDE display_payload END
+         :dedent: 4
 
 To compute the proof-of-possession signatures, run:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE sign_payload START
-   :end-before: LITERALINCLUDE sign_payload END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE sign_payload_scion_pki START
+         :end-before: LITERALINCLUDE sign_payload_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE sign_payload START
+         :end-before: LITERALINCLUDE sign_payload END
+         :dedent: 4
 
 To compute the vote, run:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE sensitive_vote START
-   :end-before: LITERALINCLUDE sensitive_vote END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE sensitive_vote_scion_pki START
+         :end-before: LITERALINCLUDE sensitive_vote_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE sensitive_vote START
+         :end-before: LITERALINCLUDE sensitive_vote END
+         :dedent: 4
 
 .. Warning::
 
@@ -475,17 +596,45 @@ To compute the vote, run:
 
 To sanity check that the proof-of-possession signatures were created correctly, run:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_signed_payload START
-   :end-before: LITERALINCLUDE check_signed_payload END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_signed_payload_scion_pki START
+         :end-before: LITERALINCLUDE check_signed_payload_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_signed_payload START
+         :end-before: LITERALINCLUDE check_signed_payload END
+         :dedent: 4
 
 To sanity check that the vote was cast correctly, run:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_sensitive_vote START
-   :end-before: LITERALINCLUDE check_sensitive_vote END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_sensitive_vote_scion_pki START
+         :end-before: LITERALINCLUDE check_sensitive_vote_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_sensitive_vote START
+         :end-before: LITERALINCLUDE check_sensitive_vote END
+         :dedent: 4
 
 Connect the *USB flash drive* to the *device*, and copy ``$TRCID.regular.trc``,
 ``$TRCID.sensitive.trc``, and ``$TRCID.sensitive.vote.trc`` to the folder named
@@ -516,10 +665,16 @@ If the sum differs, then **Phase 3** and **Phase 4** need to be repeated.
 Next, check that all the fields are consistent with earlier choices. To print the fields
 that are present in the TRC, run:
 
-.. literalinclude:: trc_ceremony_sensitive.sh
-   :start-after: LITERALINCLUDE trc_content_rep START
-   :end-before: LITERALINCLUDE trc_content_rep END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: trc_ceremony_sensitive.sh
+         :start-after: LITERALINCLUDE trc_content_rep START
+         :end-before: LITERALINCLUDE trc_content_rep END
+         :dedent: 4
 
 If there is a mismatch between any of the fields and the desired policy, then
 **Phase 3** and **Phase 4** need to be repeated.
@@ -538,7 +693,7 @@ Inform the *ceremony administrator* of the outcome of the verification.
    format instead of the raw ASN.1 DER encoding. You can do so by running the
    following command:
 
-   .. literalinclude:: trc_ceremony.sh
+   .. literalinclude:: trc_ceremony_sensitive.sh
       :start-after: LITERALINCLUDE format_trc START
       :end-before: LITERALINCLUDE format_trc END
       :dedent: 4
diff --git a/doc/cryptography/trc-signing-ceremony-preparations.rst b/doc/cryptography/trc-signing-ceremony-preparations.rst
index cf49ec49a..8f2be2ab7 100644
--- a/doc/cryptography/trc-signing-ceremony-preparations.rst
+++ b/doc/cryptography/trc-signing-ceremony-preparations.rst
@@ -10,7 +10,7 @@ preparation for the ceremony. This document outlines these steps.
 .. important::
 
    It is required that the machine used to execute the commands has openssl
-   version 1.1.1d or higher installed.
+   version 3.0.14 or higher installed.
 
 .. note::
 
@@ -83,29 +83,58 @@ Navigate to the public directory:
    :end-before: LITERALINCLUDE navigate_pubdir END
    :dedent: 4
 
-This directory stores the openssl configurations, the CSRs and the created
-certificates. To avoid duplicated information, create a ``basic.cnf`` that can
-be imported from the sensitive voting, regular voting and root certificate
-configuration files:
+This directory stores the necessary configurations and created certificates.
+Private keys are kept in a separate directory to avoid accidental disclosure.
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE basic_conf START
-   :end-before: LITERALINCLUDE basic_conf END
+.. tab-set::
+   :sync-group: tool
 
-Fill in the required fields.
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-.. note::
+      To avoid duplicated information, create a ``subject.tmpl`` that can
+      be reused for the sensitive voting, regular voting and root certificate:
 
-   The ``{{.Country}}`` must be replaced with an ISO 3166-1 alpha-2 code.
-   Switzerland, for example, has the code ``CH``.
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE basic_conf_scion_pki START
+         :end-before: LITERALINCLUDE basic_conf_scion_pki END
 
-To set the start and end time of a X509 certificate using openssl, the ``ca``
-command is necessary. The directory needs to be prepared:
+      Fill in the required fields.
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE prepare_ca START
-   :end-before: LITERALINCLUDE prepare_ca END
-   :dedent: 4
+      .. note::
+
+         The ``{{.Country}}`` must be replaced with an ISO 3166-1 alpha-2 code.
+         Switzerland, for example, has the code ``CH``.
+
+      The ``{{.ShortOrg}}`` must be replaced with a short name for the
+      organization that will be used in the certificate common name.
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+
+      To avoid duplicated information, create a ``basic.cnf`` that can
+      be imported from the sensitive voting, regular voting and root certificate
+      configuration files:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE basic_conf START
+         :end-before: LITERALINCLUDE basic_conf END
+
+      Fill in the required fields.
+
+      .. note::
+
+         The ``{{.Country}}`` must be replaced with an ISO 3166-1 alpha-2 code.
+         Switzerland, for example, has the code ``CH``.
+
+      To set the start and end time of a X509 certificate using openssl, the ``ca``
+      command is necessary. The directory needs to be prepared:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE prepare_ca START
+         :end-before: LITERALINCLUDE prepare_ca END
+         :dedent: 4
 
 
 Sensitive voting
@@ -119,12 +148,27 @@ This step creates a sensitive voting key and certificate.
    party has an AS identifier, the ISD number must match with the TRC this
    certificate will be used in.
 
-First, create the sensitive voting certificate configuration. In the file,
-replace ``{{.ShortOrg}}`` with the name of your organization:
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE sensitive_conf START
-   :end-before: LITERALINCLUDE sensitive_conf END
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      First, export the sensitive voting certificate common name.
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE sensitive_cn START
+         :end-before: LITERALINCLUDE sensitive_cn END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      First, create the sensitive voting certificate configuration. In the file,
+      replace ``{{.ShortOrg}}`` with the name of your organization:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE sensitive_conf START
+         :end-before: LITERALINCLUDE sensitive_conf END
 
 .. note::
 
@@ -145,33 +189,57 @@ replace ``{{.ShortOrg}}`` with the name of your organization:
       :end-before: LITERALINCLUDE version_sensitive END
       :dedent: 4
 
+.. tab-set::
+   :sync-group: tool
 
-Using this configuration, create the sensitive voting key and certificate. The
-start and end date need to be replaced with the time when the certificate
-becomes valid, and the time when it expires. The format is ``YYYYMMDDHHMMSSZ``.
-For example, June 24th, 2020 UTC at noon, is formatted as ``20200624120000Z``.
-The required commands are:
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE gen_sensitive START
-   :end-before: LITERALINCLUDE gen_sensitive END
-   :dedent: 4
+      Using the subject template, create the sensitive voting key and certificate. The
+      start and end date need to be replaced with the time when the certificate
+      becomes valid, and the time when it expires. The format is RFC3339 compliant.
+      For example, June 24th, 2020 UTC at noon, is formatted as ``2020-06-24T12:00:00Z``.
 
-After generating the certificate, check that the output is reasonable:
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_sensitive_scion_pki START
+         :end-before: LITERALINCLUDE gen_sensitive_scion_pki END
+         :dedent: 4
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_sensitive START
-   :end-before: LITERALINCLUDE check_sensitive END
-   :dedent: 4
+   .. tab-item:: openssl
+      :sync: openssl
+
+      Using this configuration, create the sensitive voting key and certificate. The
+      start and end date need to be replaced with the time when the certificate
+      becomes valid, and the time when it expires. The format is ``YYYYMMDDHHMMSSZ``.
+      For example, June 24th, 2020 UTC at noon, is formatted as ``20200624120000Z``.
+      The required commands are:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_sensitive START
+         :end-before: LITERALINCLUDE gen_sensitive END
+         :dedent: 4
+
+      After generating the certificate, check that the output is reasonable:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_sensitive START
+         :end-before: LITERALINCLUDE check_sensitive END
+         :dedent: 4
 
 The validity time must cover the agreed upon TRC validity period.
 
 The certificate can be validated with with the ``scion-pki`` binary:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_sensitive_type START
-   :end-before: LITERALINCLUDE check_sensitive_type END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_sensitive_type START
+         :end-before: LITERALINCLUDE check_sensitive_type END
+         :dedent: 4
 
 Regular voting
 --------------
@@ -184,11 +252,26 @@ This step creates a regular voting key and certificate.
    party has an AS identifier, the ISD number must match with the TRC this
    certificate will be used in.
 
-Create the regular voting certificate configuration:
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE regular_conf START
-   :end-before: LITERALINCLUDE regular_conf END
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      First, export the regular voting certificate common name.
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE regular_cn START
+         :end-before: LITERALINCLUDE regular_cn END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      Create the regular voting certificate configuration:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE regular_conf START
+         :end-before: LITERALINCLUDE regular_conf END
 
 .. note::
 
@@ -209,32 +292,57 @@ Create the regular voting certificate configuration:
       :end-before: LITERALINCLUDE version_regular END
       :dedent: 4
 
-Using this configuration, create the regular voting key and certificate. The
-start and end date need to be replaced with the time when the certificate
-becomes valid, and the time when it expires. The format is ``YYYYMMDDHHMMSSZ``.
-For example, June 24th, 2020 UTC at noon, is formatted as ``20200624120000Z``.
-The required commands are:
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE gen_regular START
-   :end-before: LITERALINCLUDE gen_regular END
-   :dedent: 4
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-After generating the certificate, check that the output is reasonable:
+      Using the subject template, create the regular voting key and certificate. The
+      start and end date need to be replaced with the time when the certificate
+      becomes valid, and the time when it expires. The format is RFC3339 compliant.
+      For example, June 24th, 2020 UTC at noon, is formatted as ``2020-06-24T12:00:00Z``.
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_regular START
-   :end-before: LITERALINCLUDE check_regular END
-   :dedent: 4
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_regular_scion_pki START
+         :end-before: LITERALINCLUDE gen_regular_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      Using this configuration, create the regular voting key and certificate. The
+      start and end date need to be replaced with the time when the certificate
+      becomes valid, and the time when it expires. The format is ``YYYYMMDDHHMMSSZ``.
+      For example, June 24th, 2020 UTC at noon, is formatted as ``20200624120000Z``.
+      The required commands are:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_regular START
+         :end-before: LITERALINCLUDE gen_regular END
+         :dedent: 4
+
+      After generating the certificate, check that the output is reasonable:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_regular START
+         :end-before: LITERALINCLUDE check_regular END
+         :dedent: 4
 
 The validity time must cover the agreed upon TRC validity period.
 
 The certificate can be validated with with the ``scion-pki`` binary:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_regular_type START
-   :end-before: LITERALINCLUDE check_regular_type END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_regular_type START
+         :end-before: LITERALINCLUDE check_regular_type END
+         :dedent: 4
 
 CP Root
 -------
@@ -245,11 +353,26 @@ This step creates a CP root key and certificate.
 
    This step only has to be executed by issuing ASes.
 
-Create the CP root certificate configuration:
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE root_conf START
-   :end-before: LITERALINCLUDE root_conf END
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      First, export the root certificate common name.
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE root_cn START
+         :end-before: LITERALINCLUDE root_cn END
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      Create the CP root certificate configuration:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE root_conf START
+         :end-before: LITERALINCLUDE root_conf END
 
 .. note::
 
@@ -270,29 +393,54 @@ Create the CP root certificate configuration:
       :end-before: LITERALINCLUDE version_regular END
       :dedent: 4
 
-Using this configuration, create the CP root key and certificate. The start and
-end date need to be replaced with the time when the certificate becomes valid,
-and the time when it expires. The format is ``YYYYMMDDHHMMSSZ``. For example,
-June 24th, 2020 UTC at noon, is formatted as ``20200624120000Z``. The required
-commands are:
+.. tab-set::
+   :sync-group: tool
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE gen_root START
-   :end-before: LITERALINCLUDE gen_root END
-   :dedent: 4
+   .. tab-item:: scion-pki
+      :sync: scion-pki
 
-After generating the certificate, check that the output is reasonable:
+      Using the subject template, create the root key and certificate. The
+      start and end date need to be replaced with the time when the certificate
+      becomes valid, and the time when it expires. The format is RFC3339 compliant.
+      For example, June 24th, 2020 UTC at noon, is formatted as ``2020-06-24T12:00:00Z``.
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_root START
-   :end-before: LITERALINCLUDE check_root END
-   :dedent: 4
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_root_scion_pki START
+         :end-before: LITERALINCLUDE gen_root_scion_pki END
+         :dedent: 4
+
+   .. tab-item:: openssl
+      :sync: openssl
+
+      Using this configuration, create the CP root key and certificate. The start and
+      end date need to be replaced with the time when the certificate becomes valid,
+      and the time when it expires. The format is ``YYYYMMDDHHMMSSZ``. For example,
+      June 24th, 2020 UTC at noon, is formatted as ``20200624120000Z``. The required
+      commands are:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE gen_root START
+         :end-before: LITERALINCLUDE gen_root END
+         :dedent: 4
+
+      After generating the certificate, check that the output is reasonable:
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_root START
+         :end-before: LITERALINCLUDE check_root END
+         :dedent: 4
 
 The validity time must cover the agreed upon TRC validity period.
 
 The certificate can be validated with with the ``scion-pki`` binary:
 
-.. literalinclude:: crypto_lib.sh
-   :start-after: LITERALINCLUDE check_root_type START
-   :end-before: LITERALINCLUDE check_root_type END
-   :dedent: 4
+.. tab-set::
+   :sync-group: tool
+
+   .. tab-item:: scion-pki
+      :sync: scion-pki
+
+      .. literalinclude:: crypto_lib.sh
+         :start-after: LITERALINCLUDE check_root_type START
+         :end-before: LITERALINCLUDE check_root_type END
+         :dedent: 4
diff --git a/doc/requirements.in b/doc/requirements.in
index 3e47a367e..2d5b3ab02 100644
--- a/doc/requirements.in
+++ b/doc/requirements.in
@@ -1,7 +1,8 @@
-Sphinx
 recommonmark
-sphinx-autobuild
-sphinx-rtd-theme
-sphinxcontrib-openapi
+Sphinx
 sphinx_copybutton
+sphinx_design
+sphinx-autobuild
 sphinx-lint
+sphinx-rtd-theme
+sphinxcontrib-openapi
\ No newline at end of file
diff --git a/doc/requirements.txt b/doc/requirements.txt
index 092c61e70..b0635d695 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -314,7 +314,7 @@ pyyaml==6.0.1 \
 recommonmark==0.7.1 \
     --hash=sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f \
     --hash=sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67
-    # via -r requirements.in
+    # via -r doc/requirements.in
 referencing==0.34.0 \
     --hash=sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844 \
     --hash=sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4
@@ -539,10 +539,11 @@ sphinx==7.3.7 \
     --hash=sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3 \
     --hash=sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc
     # via
-    #   -r requirements.in
+    #   -r doc/requirements.in
     #   recommonmark
     #   sphinx-autobuild
     #   sphinx-copybutton
+    #   sphinx-design
     #   sphinx-rtd-theme
     #   sphinxcontrib-httpdomain
     #   sphinxcontrib-jquery
@@ -550,15 +551,19 @@ sphinx==7.3.7 \
 sphinx-autobuild==2024.4.16 \
     --hash=sha256:1c0ed37a1970eed197f9c5a66d65759e7c4e4cba7b5a5d77940752bf1a59f2c7 \
     --hash=sha256:f2522779d30fcbf0253e09714f274ce8c608cb6ebcd67922b1c54de59faba702
-    # via -r requirements.in
+    # via -r doc/requirements.in
 sphinx-copybutton==0.5.2 \
     --hash=sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd \
     --hash=sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e
-    # via -r requirements.in
+    # via -r doc/requirements.in
+sphinx-design==0.6.0 \
+    --hash=sha256:e9bd07eecec82eb07ff72cb50fc3624e186b04f5661270bc7b62db86c7546e95 \
+    --hash=sha256:ec8e3c5c59fed4049b3a5a2e209360feab31829346b5f6a0c7c342b894082192
+    # via -r doc/requirements.in
 sphinx-lint==0.9.1 \
     --hash=sha256:185cee19ff1129549c45e15a3b25404daeb47c54d15112dda589cedad82957aa \
     --hash=sha256:df34271ab65ce43676cbd90726f4dea5cd200b43b01448b2aee8f06e609edcbb
-    # via -r requirements.in
+    # via -r doc/requirements.in
 sphinx-mdinclude==0.6.0 \
     --hash=sha256:764b6aeee28002b9d02060758266761a2c724805594d264b19e6ceeaa3bad393 \
     --hash=sha256:b1cb4dfa22ce17ca20e90e34d4349d8a97c5052709d9c4eed051cdabb615b20b
@@ -566,7 +571,7 @@ sphinx-mdinclude==0.6.0 \
 sphinx-rtd-theme==2.0.0 \
     --hash=sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b \
     --hash=sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586
-    # via -r requirements.in
+    # via -r doc/requirements.in
 sphinxcontrib-applehelp==1.0.8 \
     --hash=sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619 \
     --hash=sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4
@@ -594,7 +599,7 @@ sphinxcontrib-jsmath==1.0.1 \
 sphinxcontrib-openapi==0.8.4 \
     --hash=sha256:50911c18d452d9390ee3a384ef8dc8bde6135f542ba55691f81e1fbc0b71014e \
     --hash=sha256:df883808a5b5e4b4113ad697185c43a3f42df3dce70453af78ba7076907e9a20
-    # via -r requirements.in
+    # via -r doc/requirements.in
 sphinxcontrib-qthelp==1.0.7 \
     --hash=sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6 \
     --hash=sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182
diff --git a/pkg/scrypto/cppki/trc.go b/pkg/scrypto/cppki/trc.go
index a2398bdeb..fc300d8c3 100644
--- a/pkg/scrypto/cppki/trc.go
+++ b/pkg/scrypto/cppki/trc.go
@@ -153,7 +153,11 @@ func (trc *TRC) Validate() error {
 		}
 		if !(Validity{NotBefore: cert.NotBefore, NotAfter: cert.NotAfter}).Covers(trc.Validity) {
 			return serrors.JoinNoStack(ErrTRCValidityNotCovered, nil,
-				"subject", cert.Subject, "index", i)
+				"cert.subject", cert.Subject,
+				"cert.index", i,
+				"cert.validity", Validity{NotBefore: cert.NotBefore, NotAfter: cert.NotAfter},
+				"trc.validity", trc.Validity,
+			)
 		}
 	}
 	// Check that issuer-SN pair is unique.
diff --git a/scion-pki/cmd/scion-pki/version.go b/scion-pki/cmd/scion-pki/version.go
index 32cde3706..06b8a8015 100644
--- a/scion-pki/cmd/scion-pki/version.go
+++ b/scion-pki/cmd/scion-pki/version.go
@@ -23,7 +23,7 @@ import (
 )
 
 func newVersion() *cobra.Command {
-	major, minor, patch := 0, 5, 0
+	major, minor, patch := 0, 6, 0
 	cmd := &cobra.Command{
 		Use:   "version",
 		Short: "Show the scion-pki version information",
diff --git a/scion-pki/conf/trc.go b/scion-pki/conf/trc.go
index 6c62bcf01..dd059f255 100644
--- a/scion-pki/conf/trc.go
+++ b/scion-pki/conf/trc.go
@@ -51,6 +51,9 @@ func LoadTRC(file string) (TRC, error) {
 	if err := config.LoadFile(file, &cfg); err != nil {
 		return TRC{}, serrors.Wrap("unable to load TRC config from file", err, "file", file)
 	}
+	if err := cfg.Validity.Validate(); err != nil {
+		return TRC{}, serrors.Wrap("validating 'validity' section", err)
+	}
 	cfg.relPath = filepath.Dir(file)
 	return cfg, nil
 }
diff --git a/scion-pki/conf/validity.go b/scion-pki/conf/validity.go
index 838ea40fe..c9fc1cc1f 100644
--- a/scion-pki/conf/validity.go
+++ b/scion-pki/conf/validity.go
@@ -15,6 +15,7 @@
 package conf
 
 import (
+	"strconv"
 	"time"
 
 	"github.com/scionproto/scion/pkg/private/serrors"
@@ -22,16 +23,42 @@ import (
 	"github.com/scionproto/scion/pkg/scrypto/cppki"
 )
 
+type Time time.Time
+
+func (t Time) Time() time.Time {
+	return time.Time(t)
+}
+
+func (t *Time) UnmarshalText(b []byte) error {
+	unix, err := strconv.ParseUint(string(b), 10, 32)
+	if err == nil {
+		if unix == 0 {
+			*t = Time{}
+			return nil
+		}
+		*t = Time(util.SecsToTime(uint32(unix)))
+		return nil
+	}
+
+	parsed, err := time.Parse(time.RFC3339, string(b))
+	if err != nil {
+		return serrors.Wrap("unable to parse time", err)
+	}
+	*t = Time(parsed)
+	return nil
+}
+
 // Validity defines a validity period.
 type Validity struct {
-	NotBefore uint32       `toml:"not_before"`
+	NotBefore Time         `toml:"not_before"`
+	NotAfter  Time         `toml:"not_after"`
 	Validity  util.DurWrap `toml:"validity"`
 }
 
 // Validate checks that the validity is set.
-func (v Validity) Validate() error {
-	if v.Validity.Duration == 0 {
-		return serrors.New("validity period not set")
+func (v *Validity) Validate() error {
+	if (v.Validity.Duration == 0) == (v.NotAfter.Time().IsZero()) {
+		return serrors.New("exactly one of 'validity' or 'not_after' must be set")
 	}
 	return nil
 }
@@ -39,11 +66,16 @@ func (v Validity) Validate() error {
 // Eval returns the validity period. The not before parameter is only used if
 // the struct's not before field value is zero.
 func (v Validity) Eval(notBefore time.Time) cppki.Validity {
-	if v.NotBefore != 0 {
-		notBefore = util.SecsToTime(v.NotBefore)
+	if nb := time.Time(v.NotBefore); !nb.IsZero() {
+		notBefore = nb
 	}
 	return cppki.Validity{
 		NotBefore: notBefore,
-		NotAfter:  notBefore.Add(v.Validity.Duration),
+		NotAfter: func() time.Time {
+			if !v.NotAfter.Time().IsZero() {
+				return v.NotAfter.Time()
+			}
+			return notBefore.Add(v.Validity.Duration)
+		}(),
 	}
 }
diff --git a/scion-pki/trcs/BUILD.bazel b/scion-pki/trcs/BUILD.bazel
index e995b0dd9..832d1f409 100644
--- a/scion-pki/trcs/BUILD.bazel
+++ b/scion-pki/trcs/BUILD.bazel
@@ -7,7 +7,7 @@ go_library(
         "decode.go",
         "extract.go",
         "format.go",
-        "human.go",
+        "inspect.go",
         "payload.go",
         "sign.go",
         "toasn.go",
@@ -40,7 +40,7 @@ go_test(
         "decoded_test.go",
         "export_test.go",
         "format_test.go",
-        "human_test.go",
+        "inspect_test.go",
         "sign_test.go",
         "toasn_test.go",
         "verify_test.go",
@@ -69,7 +69,7 @@ go_test(
         "decoded_test.go",
         "export_test.go",
         "format_test.go",
-        "human_test.go",
+        "inspect_test.go",
         "sign_test.go",
         "toasn_test.go",
         "verify_test.go",
diff --git a/scion-pki/trcs/human.go b/scion-pki/trcs/inspect.go
similarity index 97%
rename from scion-pki/trcs/human.go
rename to scion-pki/trcs/inspect.go
index 17f12384e..a46153206 100644
--- a/scion-pki/trcs/human.go
+++ b/scion-pki/trcs/inspect.go
@@ -51,10 +51,10 @@ func newHuman(pather command.Pather) *cobra.Command {
 	cmd := &cobra.Command{
 		Use:     "inspect",
 		Aliases: []string{"human"},
-		Short:   "Represent TRC in a human readable form",
-		Example: fmt.Sprintf(`  %[1]s human ISD1-B1-S1.pld.der
-  %[1]s human ISD1-B1-S1.trc`, pather.CommandPath()),
-		Long: `'human' outputs the TRC contents in a human readable form.
+		Short:   "Print TRC details in a human readable format",
+		Example: fmt.Sprintf(`  %[1]s inspect ISD1-B1-S1.pld.der
+  %[1]s inspect ISD1-B1-S1.trc`, pather.CommandPath()),
+		Long: `'inspect' prints the details of a TRC a human-readable fromat.
 
 The input file can either be a TRC payload, or a signed TRC.
 The output can either be in yaml, or json.
diff --git a/scion-pki/trcs/human_test.go b/scion-pki/trcs/inspect_test.go
similarity index 100%
rename from scion-pki/trcs/human_test.go
rename to scion-pki/trcs/inspect_test.go
diff --git a/tools/buildrill/_check_gazelle_mode b/tools/buildrill/_check_gazelle_mode
new file mode 100755
index 000000000..84083e164
--- /dev/null
+++ b/tools/buildrill/_check_gazelle_mode
@@ -0,0 +1,12 @@
+#! /bin/bash
+
+# In diff mode, we expect no changes (exit code 3)
+if [[ "$GAZELLE_MODE" == "diff" ]]; then
+    test $ret -eq 3 && exit 0
+    exit 1
+fi
+
+# In fix mode, we succeed even if there are changes.
+test $ret -eq 0 && exit 0
+test $ret -eq 3 && exit 0
+exit 1
diff --git a/tools/cryptoplayground/BUILD.bazel b/tools/cryptoplayground/BUILD.bazel
index 8e23fc87a..c2a69d910 100644
--- a/tools/cryptoplayground/BUILD.bazel
+++ b/tools/cryptoplayground/BUILD.bazel
@@ -18,6 +18,23 @@ sh_test(
     ],
 )
 
+sh_test(
+    name = "trc_ceremony_scion_pki_test",
+    srcs = ["trc_ceremony.sh"],
+    data = [
+        ":crypto_lib.sh",
+        "//scion-pki/cmd/scion-pki",
+    ],
+    env = {
+        "SCION_PKI_BIN": "$(location //scion-pki/cmd/scion-pki)",
+        "USE_SCION_PKI_SIGN": "1",
+    },
+    tags = [
+        "exclusive",
+        "integration",
+    ],
+)
+
 sh_test(
     name = "trc_ceremony_sensitive_test",
     srcs = ["trc_ceremony_sensitive.sh"],
@@ -34,3 +51,21 @@ sh_test(
         "integration",
     ],
 )
+
+sh_test(
+    name = "trc_ceremony_sensitive_scion_pki_test",
+    srcs = ["trc_ceremony_sensitive.sh"],
+    data = [
+        "trc_ceremony.sh",
+        ":crypto_lib.sh",
+        "//scion-pki/cmd/scion-pki",
+    ],
+    env = {
+        "SCION_PKI_BIN": "$(location //scion-pki/cmd/scion-pki)",
+        "USE_SCION_PKI_SIGN": "1",
+    },
+    tags = [
+        "exclusive",
+        "integration",
+    ],
+)
diff --git a/tools/cryptoplayground/crypto_lib.sh b/tools/cryptoplayground/crypto_lib.sh
index bce3f54f9..6bdb1e0dd 100644
--- a/tools/cryptoplayground/crypto_lib.sh
+++ b/tools/cryptoplayground/crypto_lib.sh
@@ -91,7 +91,7 @@ in_docker() {
         -e ENDDATE=$ENDDATE \
         -e TRCID=$TRCID \
         -e PREDID=$PREDID \
-        emberstack/openssl \
+        nginx:1.27.1 \
         sh -c "set -e && . /scripts/crypto_lib.sh && $@"
 }
 
@@ -106,8 +106,8 @@ PAYLOAD_CONF_SAMPLE=$(cat <<-END
 {{.VotingQuorum}}      = 2
 {{.CoreASes}}          = ["ff00:0:110", "ff00:0:111"]
 {{.AuthoritativeASes}} = ["ff00:0:110", "ff00:0:111"]
-{{.NotBefore}}         = 1593000000  # Seconds since UNIX Epoch
-{{.Validity}}          = "365d"
+{{.NotBefore}}         = "2020-06-24T14:00:00+02:00"  # RFC3339
+{{.NotAfter}}          = "2021-06-24T14:00:00+02:00"
 {{.CertFiles}} = [
     "bern/sensitive-voting.crt",
     "bern/regular-voting.crt",
@@ -136,7 +136,7 @@ no_trust_reset     = false
 
 [validity]
 not_before = {{.NotBefore}}
-validity   = {{.Validity}}
+not_after   = {{.NotAfter}}
 EOF
 # LITERALINCLUDE payload_conf END
 }
@@ -151,8 +151,8 @@ SENSITIVE_PAYLOAD_CONF_SAMPLE=$(cat <<-END
 {{.Votes}}             = [0, 3, 5]
 {{.CoreASes}}          = ["ff00:0:110", "ff00:0:111"]
 {{.AuthoritativeASes}} = ["ff00:0:110", "ff00:0:111"]
-{{.NotBefore}}         = 1621857600  # Seconds since UNIX Epoch
-{{.Validity}}          = "365d"
+{{.NotBefore}}         = "2021-05-24T14:00:00+02:00"  # RFC3339
+{{.NotAfter}}          = "2022-05-24T14:00:00+02:00"
 {{.CertFiles}} = [
     "bern/sensitive-voting.crt",
     "bern/regular-voting.crt",
@@ -183,7 +183,7 @@ no_trust_reset     = false
 
 [validity]
 not_before = {{.NotBefore}}
-validity   = {{.Validity}}
+not_after   = {{.NotAfter}}
 EOF
 # LITERALINCLUDE sensitive_payload_conf END
 }
@@ -237,6 +237,23 @@ EOF
 # LITERALINCLUDE basic_conf END
 }
 
+basic_conf_scion_pki() {
+# LITERALINCLUDE basic_conf_scion_pki START
+cat << EOF > subject.tmpl
+{
+    "country": "{{.Country}}",
+    "state": "{{.State}}",
+    "locality": "{{.Location}}",
+    "organization": "{{.Organization}}",
+    "organizational_unit": "{{.OrganizationalUnit}}",
+    "isd_as": "{{.ISDAS}}"
+}
+EOF
+
+export ORG="{{.ShortOrg}}"
+# LITERALINCLUDE basic_conf_scion_pki END
+}
+
 prepare_ca() {
 # LITERALINCLUDE prepare_ca START
     mkdir -p database
@@ -266,6 +283,12 @@ EOF
 # LITERALINCLUDE sensitive_conf END
 }
 
+sensitive_cn() {
+# LITERALINCLUDE sensitive_cn START
+export CN_SENSITIVE="$ORG High Security Voting Certificate"
+# LITERALINCLUDE sensitive_cn END
+}
+
 regular_conf() {
 # LITERALINCLUDE regular_conf START
 cat << EOF > regular-voting.cnf
@@ -287,6 +310,12 @@ EOF
 # LITERALINCLUDE regular_conf END
 }
 
+regular_cn() {
+# LITERALINCLUDE regular_cn START
+export CN_REGULAR="$ORG Regular Voting Certificate"
+# LITERALINCLUDE regular_cn END
+}
+
 root_conf() {
 # LITERALINCLUDE root_conf START
 cat << EOF > cp-root.cnf
@@ -310,6 +339,12 @@ EOF
 # LITERALINCLUDE root_conf END
 }
 
+root_cn() {
+# LITERALINCLUDE root_cn START
+export CN_ROOT="$ORG High Security Root Certificate"
+# LITERALINCLUDE root_cn END
+}
+
 ca_conf() {
 # LITERALINCLUDE ca_conf START
 cat << EOF > cp-ca.cnf
@@ -392,6 +427,25 @@ gen_sensitive() {
 # LITERALINCLUDE gen_sensitive END
 }
 
+gen_sensitive_scion_pki() {
+# LITERALINCLUDE gen_sensitive_scion_pki START
+    # Uncomment and set the appropriate values:
+    #
+    # STARTDATE="2020-06-24T14:00:00+02:00"
+    # ENDDATE="2021-06-24T14:00:00+02:00"
+
+    scion-pki certificate create \
+        --profile sensitive-voting \
+        --not-before $STARTDATE \
+        --not-after $ENDDATE \
+        --common-name "$CN_SENSITIVE" \
+        subject.tmpl \
+        sensitive-voting.crt \
+        $KEYDIR/sensitive-voting.key
+# LITERALINCLUDE gen_sensitive_scion_pki END
+}
+
+
 check_sensitive() {
 # LITERALINCLUDE check_sensitive START
     openssl x509 -in sensitive-voting.crt -noout -dates
@@ -437,6 +491,24 @@ gen_regular() {
 # LITERALINCLUDE gen_regular END
 }
 
+gen_regular_scion_pki() {
+# LITERALINCLUDE gen_regular_scion_pki START
+    # Uncomment and set the appropriate values:
+    #
+    # STARTDATE="2020-06-24T14:00:00+02:00"
+    # ENDDATE="2021-06-24T14:00:00+02:00"
+
+    scion-pki certificate create \
+        --profile regular-voting \
+        --not-before $STARTDATE \
+        --not-after $ENDDATE \
+        --common-name "$CN_REGULAR" \
+        subject.tmpl \
+        regular-voting.crt \
+        $KEYDIR/regular-voting.key
+# LITERALINCLUDE gen_regular_scion_pki END
+}
+
 check_regular() {
 # LITERALINCLUDE check_regular START
     openssl x509 -in regular-voting.crt -noout -dates
@@ -482,6 +554,25 @@ gen_root() {
 # LITERALINCLUDE gen_root END
 }
 
+
+gen_root_scion_pki() {
+# LITERALINCLUDE gen_root_scion_pki START
+    # Uncomment and set the appropriate values:
+    #
+    # STARTDATE="2020-06-24T14:00:00+02:00"
+    # ENDDATE="2021-06-24T14:00:00+02:00"
+
+    scion-pki certificate create \
+        --profile cp-root \
+        --not-before $STARTDATE \
+        --not-after $ENDDATE \
+        --common-name "$CN_ROOT" \
+        subject.tmpl \
+        cp-root.crt \
+        $KEYDIR/cp-root.key
+# LITERALINCLUDE gen_root_scion_pki END
+}
+
 check_root() {
 # LITERALINCLUDE check_root START
     openssl x509 -in cp-root.crt -noout -dates
@@ -527,6 +618,26 @@ gen_ca() {
 # LITERALINCLUDE gen_ca END
 }
 
+gen_ca_scion_pki() {
+# LITERALINCLUDE gen_ca_scion_pki START
+    # Uncomment and set the appropriate values:
+    #
+    # STARTDATE="2020-06-24T14:00:00+02:00"
+    # ENDDATE="2020-07-01T14:00:00+02:00"
+
+    scion-pki certificate create \
+        --ca cp-root.crt \
+        --ca-key $KEYDIR/cp-root.key \
+        --not-before $STARTDATE \
+        --not-after $ENDDATE \
+        --common-name "$ORG Secure CA Certificate" \
+        --profile cp-ca \
+        subject.tmpl \
+        cp-ca.crt \
+        $KEYDIR/cp-ca.key
+# LITERALINCLUDE gen_ca_scion_pki END
+}
+
 check_ca() {
 # LITERALINCLUDE check_ca START
     openssl x509 -in cp-ca.crt -noout -dates
@@ -569,6 +680,33 @@ gen_as_ca_steps() {
 # LITERALINCLUDE gen_as_ca_steps END
 }
 
+gen_as_scion_pki() {
+# LITERALINCLUDE gen_as_scion_pki_as_steps START
+    scion-pki certificate create \
+        --profile cp-as \
+        --common-name "$ORG AS Certificate" \
+        --csr \
+        subject.tmpl \
+        cp-as.csr \
+        $KEYDIR/cp-as.key
+# LITERALINCLUDE gen_as_scion_pki_as_steps END
+# LITERALINCLUDE gen_as_scion_pki_ca_steps START
+    # Uncomment and set the appropriate values:
+    #
+    # STARTDATE="2020-06-24T14:00:00+02:00"
+    # ENDDATE="2020-06-27T14:00:00+02:00"
+
+    scion-pki certificate sign \
+        --bundle \
+        --ca cp-ca.crt \
+        --ca-key $KEYDIR/cp-ca.key \
+        --not-before $STARTDATE \
+        --not-after $ENDDATE \
+        cp-as.csr \
+        > chain.pem
+# LITERALINCLUDE gen_as_scion_pki_ca_steps END
+}
+
 check_as() {
 # LITERALINCLUDE check_as START
     openssl x509 -in cp-as.crt -noout -dates
@@ -618,6 +756,19 @@ sign_payload() {
 # LITERALINCLUDE sign_payload END
 }
 
+sign_payload_scion_pki() {
+# LITERALINCLUDE sign_payload_scion_pki START
+    scion-pki trc sign $TRCID.pld.der \
+        $PUBDIR/regular-voting.crt \
+        $KEYDIR/regular-voting.key \
+        -o $TRCID.regular.trc
+    scion-pki trc sign $TRCID.pld.der \
+        $PUBDIR/sensitive-voting.crt \
+        $KEYDIR/sensitive-voting.key \
+        -o $TRCID.sensitive.trc
+# LITERALINCLUDE sign_payload_scion_pki END
+}
+
 sensitive_vote() {
 # LITERALINCLUDE sensitive_vote START
     openssl cms -sign -in $TRCID.pld.der -inform der \
@@ -628,6 +779,15 @@ sensitive_vote() {
 # LITERALINCLUDE sensitive_vote END
 }
 
+sensitive_vote_scion_pki() {
+# LITERALINCLUDE sensitive_vote_scion_pki START
+    scion-pki trc sign $TRCID.pld.der \
+        $PUBDIR/$PREDID/sensitive-voting.crt \
+        $KEYDIR/$PREDID/sensitive-voting.key \
+        -o $TRCID.sensitive.vote.trc
+# LITERALINCLUDE sensitive_vote_scion_pki END
+}
+
 regular_vote() {
 # LITERALINCLUDE regular_vote START
     openssl cms -sign -in $TRCID.pld.der -inform der \
@@ -638,6 +798,13 @@ regular_vote() {
 # LITERALINCLUDE regular_vote END
 }
 
+check_signed_payload_scion_pki() {
+# LITERALINCLUDE check_signed_payload_scion_pki START
+    scion-pki trc inspect $TRCID.regular.trc
+    scion-pki trc inspect $TRCID.sensitive.trc
+# LITERALINCLUDE check_signed_payload_scion_pki END
+}
+
 check_signed_payload() {
 # LITERALINCLUDE check_signed_payload START
     openssl cms -verify -in $TRCID.sensitive.trc -inform der \
@@ -681,6 +848,12 @@ check_sensitive_vote() {
 # LITERALINCLUDE check_sensitive_vote END
 }
 
+check_sensitive_vote_scion_pki() {
+# LITERALINCLUDE check_sensitive_vote_scion_pki START
+    scion-pki trc inspect $TRCID.sensitive.vote.trc
+# LITERALINCLUDE check_sensitive_vote_scion_pki END
+}
+
 check_regular_vote() {
 # LITERALINCLUDE check_regular_vote START
     openssl cms -verify -in $TRCID.regular.vote.trc -inform der \
@@ -744,6 +917,12 @@ display_payload() {
 # LITERALINCLUDE display_payload END
 }
 
+display_payload_scion_pki() {
+# LITERALINCLUDE display_payload_scion_pki START
+    scion-pki trc inspect $TRCID.pld.der
+# LITERALINCLUDE display_payload_scion_pki END
+}
+
 display_signatures() {
 # LITERALINCLUDE display_signatures START
     openssl pkcs7 -in $TRCID.trc -inform der -print -noout
@@ -757,3 +936,11 @@ display_signatures() {
     # -noout:  do not display the encoded structure.
 # LITERALINCLUDE display_signatures END
 }
+
+display_signatures_scion_pki() {
+# LITERALINCLUDE display_signatures_scion_pki START
+    scion-pki trc inspect $TRCID.trc
+# LITERALINCLUDE display_signatures_scion_pki END
+}
+
+
diff --git a/tools/cryptoplayground/trc_ceremony.sh b/tools/cryptoplayground/trc_ceremony.sh
index 896c9bc40..7405ba550 100755
--- a/tools/cryptoplayground/trc_ceremony.sh
+++ b/tools/cryptoplayground/trc_ceremony.sh
@@ -8,13 +8,19 @@ export PLAYGROUND=$(realpath "${PLAYGROUND:-$SCION_ROOT/tools/cryptoplayground}"
 export SAFEDIR=${SAFEDIR:-$(mktemp -d)}
 export SCION_PKI_BIN=${SCION_PKI_BIN:-$SCION_ROOT/bin/scion-pki}
 export PATH="$(realpath $(dirname "$SCION_PKI_BIN")):$PATH"
+export USE_SCION_PKI_SIGN=${USE_SCION_PKI_SIGN:-}
 
 . $PLAYGROUND/crypto_lib.sh
 
 set -e
 
-STARTDATE="20200624120000Z"
-ENDDATE="20210624120000Z"
+if [ -z "$USE_SCION_PKI_SIGN" ]; then
+    STARTDATE="20200624120000Z"
+    ENDDATE="20210624120000Z"
+else
+    STARTDATE="2020-06-24T14:00:00+02:00"
+    ENDDATE="2021-06-24T14:00:00+02:00"
+fi
 TRCID="ISD1-B1-S1"
 
 echo "#####################"
@@ -36,27 +42,47 @@ do
     set_dirs
     # Generate configuration files
     navigate_pubdir
-    basic_conf && sensitive_conf && regular_conf && root_conf && ca_conf && as_conf
-    prepare_ca
-    sed -i \
-        -e 's/{{.Country}}/CH/g' \
-        -e "s/{{.State}}/$loc/g" \
-        -e "s/{{.Location}}/$loc/g" \
-        -e "s/{{.Organization}}/$loc/g" \
-        -e "s/{{.OrganizationalUnit}}/$loc InfoSec Squad/g" \
-        -e "s/{{.ISDAS}}/$IA/g" \
-        basic.cnf
-    for cnf in *.cnf
-    do
+
+    if [ -z "$USE_SCION_PKI_SIGN" ]; then
+        basic_conf && sensitive_conf && regular_conf && root_conf && ca_conf && as_conf
+        prepare_ca
         sed -i \
-        -e "s/{{.ShortOrg}}/$loc/g" \
-        $cnf
-    done
-    # Generate certificates
-    in_docker 'navigate_pubdir && gen_sensitive && check_sensitive && gen_regular && check_regular && gen_root && check_root'
+            -e 's/{{.Country}}/CH/g' \
+            -e "s/{{.State}}/$loc/g" \
+            -e "s/{{.Location}}/$loc/g" \
+            -e "s/{{.Organization}}/$loc/g" \
+            -e "s/{{.OrganizationalUnit}}/$loc InfoSec Squad/g" \
+            -e "s/{{.ISDAS}}/$IA/g" \
+            basic.cnf
+        for cnf in *.cnf
+        do
+            sed -i \
+            -e "s/{{.ShortOrg}}/$loc/g" \
+            $cnf
+        done
+        # Generate certificates
+        in_docker 'navigate_pubdir && gen_sensitive && check_sensitive && gen_regular && check_regular && gen_root && check_root'
+    else
+        basic_conf_scion_pki
+        sed -i \
+            -e 's/{{.Country}}/CH/g' \
+            -e "s/{{.State}}/$loc/g" \
+            -e "s/{{.Location}}/$loc/g" \
+            -e "s/{{.Organization}}/$loc/g" \
+            -e "s/{{.OrganizationalUnit}}/$loc InfoSec Squad/g" \
+            -e "s/{{.ISDAS}}/$IA/g" \
+            subject.tmpl
+        export ORG=$loc
+        sensitive_cn && gen_sensitive_scion_pki
+        regular_cn && gen_regular_scion_pki
+        root_cn && gen_root_scion_pki
+    fi
     check_sensitive_type && check_regular_type && check_root_type
 done
 
+echo "Openssl version"
+in_docker "openssl version"
+
 echo "###########"
 echo "# Phase 1 #"
 echo "###########"
@@ -78,6 +104,13 @@ for cert in {bern,geneva,zürich}/*.crt; do
 done
 # LITERALINCLUDE display_validity END
 
+# LITERALINCLUDE display_validity_scion-pki START
+for cert in {bern,geneva,zürich}/*.crt; do
+    echo $cert
+    scion-pki certificate inspect $cert | grep Validity -A 2
+done
+# LITERALINCLUDE display_validity_scion-pki END
+
 # LITERALINCLUDE display_signature_algo START
 for cert in {bern,geneva,zürich}/*.crt; do
     echo $cert
@@ -86,6 +119,13 @@ for cert in {bern,geneva,zürich}/*.crt; do
 done
 # LITERALINCLUDE display_signature_algo END
 
+# LITERALINCLUDE display_signature_algo_scion-pki START
+for cert in {bern,geneva,zürich}/*.crt; do
+    echo $cert
+    scion-pki certificate inspect $cert | grep -m 1 "Signature Algorithm"
+done
+# LITERALINCLUDE display_signature_algo_scion-pki END
+
 # LITERALINCLUDE validate_certificate_type START
 for cert in {bern,geneva,zürich}/*.crt; do
     scion-pki certs validate --type $(basename $cert .crt) $cert
@@ -140,8 +180,8 @@ sed -i \
     -e 's/{{.VotingQuorum}}/2/g' \
     -e 's/{{.CoreASes}}/["ff00:0:110", "ff00:0:111"]/g' \
     -e 's/{{.AuthoritativeASes}}/["ff00:0:110", "ff00:0:111"]/g' \
-    -e 's/{{.NotBefore}}/1593000000/g' \
-    -e 's/{{.Validity}}/"365d"/g' \
+    -e 's/{{.NotBefore}}/"2020-06-24T14:00:00+02:00"/g' \
+    -e 's/{{.NotAfter}}/"2021-06-24T14:00:00+02:00"/g' \
     -e "s/{{.CertFiles}}/[$files]/g" \
     $TRCID.toml
 
@@ -151,7 +191,7 @@ cat $TRCID.toml
 echo "-------------------------------"
 
 # LITERALINCLUDE create_payload START
-scion-pki trcs payload -t $TRCID.toml -o $TRCID.pld.der
+scion-pki trc payload -t $TRCID.toml -o $TRCID.pld.der
 # LITERALINCLUDE create_payload END
 
 echo "Phase 2: display payload digest"
@@ -176,7 +216,13 @@ do
     cd $SAFEDIR/$loc
     set_dirs
 
-    in_docker "cd /workdir && display_payload && sign_payload && check_signed_payload"
+    display_payload_scion_pki
+    if [ -z "$USE_SCION_PKI_SIGN" ]; then
+        in_docker "cd /workdir && display_payload && sign_payload && check_signed_payload"
+    else
+        sign_payload_scion_pki
+        check_signed_payload_scion_pki
+    fi
     cp $TRCID.{regular,sensitive}.trc $SAFEDIR/admin/$loc
 done
 
@@ -188,7 +234,7 @@ echo "Phase 4: combine TRC"
 cd $SAFEDIR/admin
 
 # LITERALINCLUDE combine_payload START
-scion-pki trcs combine -p $TRCID.pld.der \
+scion-pki trc combine -p $TRCID.pld.der \
     bern/$TRCID.sensitive.trc \
     bern/$TRCID.regular.trc \
     geneva/$TRCID.sensitive.trc \
@@ -199,7 +245,7 @@ scion-pki trcs combine -p $TRCID.pld.der \
 # LITERALINCLUDE combine_payload END
 
 # LITERALINCLUDE verify_payload START
-scion-pki trcs verify --anchor $TRCID.trc $TRCID.trc
+scion-pki trc verify --anchor $TRCID.trc $TRCID.trc
 # LITERALINCLUDE verify_payload END
 in_docker "cd /workdir && verify_trc"
 
@@ -238,14 +284,21 @@ do
     navigate_pubdir
 
     echo "Phase 5: $loc generate CA certificate"
-    in_docker "navigate_pubdir && gen_ca && check_ca"
-    check_ca_type
-
+    if [ -z "$USE_SCION_PKI_SIGN" ]; then
+        in_docker "navigate_pubdir && gen_ca && check_ca"
+        check_ca_type
+    else
+        gen_ca_scion_pki
+    fi
     echo "Phase 5: $loc generate AS certificate"
-    in_docker "navigate_pubdir && gen_as && check_as"
-    check_as_type
-    cat cp-as.crt cp-ca.crt > chain.pem
-    scion-pki certs verify --trc ../$TRCID.trc --currenttime 1593000000 chain.pem
+    if [ -z "$USE_SCION_PKI_SIGN" ]; then
+        in_docker "navigate_pubdir && gen_as && check_as"
+        check_as_type
+        cat cp-as.crt cp-ca.crt > chain.pem
+    else
+        gen_as_scion_pki
+    fi
+    scion-pki certificate verify --trc ../$TRCID.trc --currenttime 1593000000 chain.pem
 done
 
 echo "###########"
diff --git a/tools/cryptoplayground/trc_ceremony_sensitive.sh b/tools/cryptoplayground/trc_ceremony_sensitive.sh
index b5fce6efe..23e627885 100755
--- a/tools/cryptoplayground/trc_ceremony_sensitive.sh
+++ b/tools/cryptoplayground/trc_ceremony_sensitive.sh
@@ -8,6 +8,7 @@ export PLAYGROUND=$(realpath "${PLAYGROUND:-$SCION_ROOT/tools/cryptoplayground}"
 export SAFEDIR=${SAFEDIR:-$(mktemp -d)}
 export SCION_PKI_BIN=${SCION_PKI_BIN:-$SCION_ROOT/bin/scion-pki}
 export PATH="$(realpath $(dirname "$SCION_PKI_BIN")):$PATH"
+export USE_SCION_PKI_SIGN=${USE_SCION_PKI_SIGN:-}
 
 . $PLAYGROUND/crypto_lib.sh
 
@@ -27,8 +28,13 @@ if [ ! -d "$SAFEDIR/admin" ]; then
     echo ""
 fi
 
-STARTDATE="20210524120000Z"
-ENDDATE="20220524120000Z"
+if [ -z "$USE_SCION_PKI_SIGN" ]; then
+    STARTDATE="20210524120000Z"
+    ENDDATE="20220524120000Z"
+else
+    STARTDATE="2021-05-24T14:00:00+02:00"
+    ENDDATE="2022-05-24T14:00:00+02:00"
+fi
 PREDID="ISD1-B1-S1"
 TRCID="ISD1-B1-S2"
 
@@ -54,9 +60,20 @@ do
 
     TRCVERSION=$PREDID && version_sensitive && version_regular && version_root
 
-    # Generate certificates
-    in_docker 'navigate_pubdir && gen_sensitive && check_sensitive && gen_regular && check_regular && gen_root && check_root'
+    if [ -z "$USE_SCION_PKI_SIGN" ]; then
+        # Generate certificates
+        in_docker 'navigate_pubdir && gen_sensitive && check_sensitive && gen_regular && check_regular && gen_root && check_root'
+    else
+        # Clean up keys and certificates from base ceremony
+        rm $KEYDIR/cp-ca.key $KEYDIR/cp-as.key cp-ca.crt cp-as.csr chain.pem
+
+        export ORG=$loc
+        sensitive_cn && gen_sensitive_scion_pki
+        regular_cn && gen_regular_scion_pki
+        root_cn && gen_root_scion_pki
+    fi
     check_sensitive_type && check_regular_type && check_root_type
+
 done
 
 echo "###########"
@@ -80,6 +97,13 @@ for cert in {bern,geneva,zürich}/*.crt; do
 done
 # LITERALINCLUDE display_validity END
 
+# LITERALINCLUDE display_validity_scion-pki START
+for cert in {bern,geneva,zürich}/*.crt; do
+    echo $cert
+    scion-pki certificate inspect $cert | grep Validity -A 2
+done
+# LITERALINCLUDE display_validity_scion-pki END
+
 # LITERALINCLUDE display_signature_algo START
 for cert in {bern,geneva,zürich}/*.crt; do
     echo $cert
@@ -88,6 +112,13 @@ for cert in {bern,geneva,zürich}/*.crt; do
 done
 # LITERALINCLUDE display_signature_algo END
 
+# LITERALINCLUDE display_signature_algo_scion-pki START
+for cert in {bern,geneva,zürich}/*.crt; do
+    echo $cert
+    scion-pki certificate inspect $cert | grep -m 1 "Signature Algorithm"
+done
+# LITERALINCLUDE display_signature_algo_scion-pki END
+
 # LITERALINCLUDE validate_certificate_type START
 for cert in {bern,geneva,zürich}/*.crt; do
     scion-pki certs validate --type $(basename $cert .crt) $cert
@@ -145,8 +176,8 @@ sed -i \
     -e 's/{{.Votes}}/[0, 3, 6]/g' \
     -e 's/{{.CoreASes}}/["ff00:0:110", "ff00:0:111"]/g' \
     -e 's/{{.AuthoritativeASes}}/["ff00:0:110", "ff00:0:111"]/g' \
-    -e 's/{{.NotBefore}}/1621857600/g' \
-    -e 's/{{.Validity}}/"365d"/g' \
+    -e 's/{{.NotBefore}}/"2021-05-24T14:00:00+02:00"/g' \
+    -e 's/{{.NotAfter}}/"2022-05-24T14:00:00+02:00"/g' \
     -e "s/{{.CertFiles}}/[$files]/g" \
     $TRCID.toml
 
@@ -181,7 +212,14 @@ do
     cd $SAFEDIR/$loc
     set_dirs
 
-    in_docker "cd /workdir && display_payload && sign_payload && check_signed_payload && sensitive_vote && check_sensitive_vote"
+    display_payload_scion_pki
+    if [ -z "$USE_SCION_PKI_SIGN" ]; then
+        in_docker "cd /workdir && display_payload && sign_payload && check_signed_payload && sensitive_vote && check_sensitive_vote"
+    else
+        sign_payload_scion_pki
+        sensitive_vote_scion_pki
+        check_signed_payload_scion_pki
+    fi
     cp $TRCID.{regular,sensitive,sensitive.vote}.trc $SAFEDIR/admin/$loc
 done
 
@@ -220,7 +258,7 @@ echo "---------------------------"
 
 echo "Phase 4: display trc contents"
 # LITERALINCLUDE trc_content START
-scion-pki trcs human --predecessor $PREDID.trc $TRCID.trc
+scion-pki trc inspect --predecessor $PREDID.trc $TRCID.trc
 # LITERALINCLUDE trc_content END
 
 for loc in {bern,geneva,zürich}
@@ -232,8 +270,12 @@ do
     set_dirs
     scion-pki trcs verify --anchor $PREDID.trc $TRCID.trc
     # LITERALINCLUDE trc_content_rep START
-    scion-pki trcs human --predecessor $PREDID.trc $TRCID.trc
+    scion-pki trc inspect --predecessor $PREDID.trc $TRCID.trc
     # LITERALINCLUDE trc_content_rep END
+
+    # LITERALINCLUDE format_trc START
+    scion-pki trc format --format pem $TRCID.trc
+    # LITERALINCLUDE format_trc END
 done
 
 echo "Phase 5: sanity check - generate CA and AS Certificates"
@@ -248,13 +290,20 @@ do
     navigate_pubdir
 
     echo "Phase 5: $loc generate CA certificate"
-    in_docker "navigate_pubdir && gen_ca && check_ca"
-    check_ca_type
-
+    if [ -z "$USE_SCION_PKI_SIGN" ]; then
+        in_docker "navigate_pubdir && gen_ca && check_ca"
+        check_ca_type
+    else
+        gen_ca_scion_pki
+    fi
     echo "Phase 5: $loc generate AS certificate"
-    in_docker "navigate_pubdir && gen_as && check_as"
-    check_as_type
-    cat cp-as.crt cp-ca.crt > chain.pem
+    if [ -z "$USE_SCION_PKI_SIGN" ]; then
+        in_docker "navigate_pubdir && gen_as && check_as"
+        check_as_type
+        cat cp-as.crt cp-ca.crt > chain.pem
+    else
+        gen_as_scion_pki
+    fi
     scion-pki certs verify --trc ../$TRCID.trc --currenttime 1621857600 chain.pem
 done
 


Test patch:
diff --git a/scion-pki/conf/testdata/testcfg.rfc3339.toml b/scion-pki/conf/testdata/testcfg.rfc3339.toml
new file mode 100644
index 000000000..98dfdaea5
--- /dev/null
+++ b/scion-pki/conf/testdata/testcfg.rfc3339.toml
@@ -0,0 +1,13 @@
+isd = 1
+description = "test config"
+serial_version = 1
+base_version = 1
+voting_quorum = 1
+no_trust_reset = false
+core_ases = ["ff00:0:110"]
+authoritative_ases = ["ff00:0:120"]
+cert_files = ["regular-voting.crt", "sensitive-voting.crt"]
+
+[validity]
+  not_before = "2024-06-24T12:13:14+02:00"
+  validity = "1h"
diff --git a/scion-pki/conf/testdata/testcfg.unix.toml b/scion-pki/conf/testdata/testcfg.unix.toml
new file mode 100644
index 000000000..a13860f8f
--- /dev/null
+++ b/scion-pki/conf/testdata/testcfg.unix.toml
@@ -0,0 +1,13 @@
+isd = 1
+description = "test config"
+serial_version = 1
+base_version = 1
+voting_quorum = 1
+no_trust_reset = false
+core_ases = ["ff00:0:110"]
+authoritative_ases = ["ff00:0:120"]
+cert_files = ["regular-voting.crt", "sensitive-voting.crt"]
+
+[validity]
+  not_before = 1719223994
+  validity = "1h"
diff --git a/scion-pki/conf/trc_test.go b/scion-pki/conf/trc_test.go
index b97dcdd56..6af098ee0 100644
--- a/scion-pki/conf/trc_test.go
+++ b/scion-pki/conf/trc_test.go
@@ -63,6 +63,7 @@ func TestLoadTRC(t *testing.T) {
 		file      string
 		cfg       conf.TRC
 		assertErr assert.ErrorAssertionFunc
+		check     func(*conf.TRC)
 	}{
 		"file not found": {
 			file:      "notfound.404",
@@ -71,14 +72,33 @@ func TestLoadTRC(t *testing.T) {
 		"valid": {
 			file:      "testdata/testcfg.toml",
 			assertErr: assert.NoError,
-			cfg:       *createTRC(t),
+			check: func(cfg *conf.TRC) {
+				assert.Equal(t, createTRC(t), cfg)
+				assert.True(t, cfg.Validity.NotBefore.Time().IsZero())
+			},
+		},
+		"unix": {
+			file:      "testdata/testcfg.unix.toml",
+			assertErr: assert.NoError,
+			check: func(cfg *conf.TRC) {
+				assert.Equal(t, int64(1719223994), cfg.Validity.NotBefore.Time().Unix())
+			},
+		},
+		"rfc3339": {
+			file:      "testdata/testcfg.rfc3339.toml",
+			assertErr: assert.NoError,
+			check: func(cfg *conf.TRC) {
+				assert.Equal(t, int64(1719223994), cfg.Validity.NotBefore.Time().Unix())
+			},
 		},
 	}
 	for name, tc := range testCases {
 		t.Run(name, func(t *testing.T) {
 			cfg, err := conf.LoadTRC(tc.file)
 			tc.assertErr(t, err)
-			assert.Equal(t, tc.cfg, cfg)
+			if tc.check != nil {
+				tc.check(&cfg)
+			}
 		})
 	}
 }
diff --git a/scion-pki/testcrypto/testcrypto.go b/scion-pki/testcrypto/testcrypto.go
index f85299877..0a819333f 100644
--- a/scion-pki/testcrypto/testcrypto.go
+++ b/scion-pki/testcrypto/testcrypto.go
@@ -313,7 +313,7 @@ func createTRCs(cfg config) error {
 			BaseVersion:   1,
 			VotingQuorum:  uint8(len(voters[isd])/2 + 1),
 			Validity: conf.Validity{
-				NotBefore: uint32(cfg.now.UTC().Unix()),
+				NotBefore: conf.Time(cfg.now.UTC()),
 				Validity:  util.DurWrap{Duration: 450 * 24 * time.Hour},
 			},
 			CoreASes:          cores[isd],
diff --git a/tools/buildrill/go_integration_test_sync b/tools/buildrill/go_integration_test_sync
new file mode 100755
index 000000000..791be4a68
--- /dev/null
+++ b/tools/buildrill/go_integration_test_sync
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+GAZELLE_MODE="${GAZELLE_MODE:-fix}"
+
+bazel run @com_github_bazelbuild_buildtools//buildozer -- \
+   --root_dir $PWD \
+  "copy deps go_default_test" \
+  "copy srcs go_default_test" \
+  "add tags integration" \
+  $(bazel query 'attr(name, "go_integration_test$", //...)' | tr '\n' ' ')
+
+ret=$?
+
+script_path=$(dirname "$0")
+. "${script_path}/_check_gazelle_mode"