Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Renew node certificate proposal #2924

Merged
merged 148 commits into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from 136 commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
7512f53
Add new table for endorsed node cert
Jul 9, 2021
706c294
Refactor san/cn into unique struct
Jul 9, 2021
753fec1
WIP something is wrong with ledger
Jul 9, 2021
34e73e4
Merge branch 'main' of github.com:microsoft/CCF into node_cert_endors…
Jul 13, 2021
6d3d0ad
Test read_ledger.py from e2e test infra
Jul 13, 2021
5db7548
WIP
Jul 13, 2021
c57c59e
Store CSR of joiner in KV
Jul 13, 2021
79eff2d
First version works
Jul 14, 2021
c146a43
Remove deprecated --domain option to cchost
Jul 14, 2021
0237e30
Merge branch 'main' into remove_domain
jumaffre Jul 14, 2021
2c73f74
Changelog
Jul 14, 2021
decc7bf
Merge branch 'remove_domain' of github.com:jumaffre/CCF into remove_d…
Jul 14, 2021
3659097
Merge branch 'remove_domain' into node_cert_endorsement
Jul 14, 2021
6d7e4fa
Return endorsed certificate in response
Jul 14, 2021
5071125
Endorsement works fine on the backup + compatibility
Jul 15, 2021
f69d8d7
Read SubjectAltName from CSR
Jul 16, 2021
7ab9dec
Merge branch 'main' of github.com:microsoft/CCF into node_cert_endors…
Jul 20, 2021
eaa7f71
Refactor arguments to CSR generation
Jul 20, 2021
5dfedd8
Remove CSI from store
Jul 20, 2021
a85bc94
Parse public key from CSR
Jul 21, 2021
258550a
Add missing &
Jul 21, 2021
9eac639
Signature verification works
Jul 21, 2021
cd9d8a1
Change type of endorsed certificates KV map
Jul 23, 2021
8acc546
Historical queries work again
Jul 23, 2021
58aba92
Merge branch 'main' of github.com:microsoft/CCF into node_cert_endors…
Jul 23, 2021
c620497
Merge branch 'main' into node_cert_endorsement
jumaffre Aug 2, 2021
63a8aeb
Merge branch 'main' of github.com:microsoft/CCF into node_cert_endors…
Aug 5, 2021
be4cd78
Record public key
Aug 5, 2021
f6c93ee
Also register CSR
Aug 5, 2021
c155191
Pick up TLS cert from hook
Aug 5, 2021
99e50d9
Merge branch 'node_cert_endorsement' of github.com:jumaffre/CCF into …
Aug 5, 2021
bedfa7f
Merge branch 'main' into node_cert_endorsement
jumaffre Aug 6, 2021
1b2ca95
Remove duplicated changelog entry
Aug 6, 2021
b02627f
Refactor verify node signature
Aug 6, 2021
d91342a
Fix n2n channel non-endorsed certificate issue
Aug 6, 2021
7dcfc8d
WIP
Aug 9, 2021
e20c8aa
operator default
Aug 9, 2021
837a1c1
Minor tweaks
Aug 9, 2021
7a5e02a
More cleanup
Aug 9, 2021
cccaf65
Fix LTS compatibility
Aug 9, 2021
7f2c85e
Merge branch 'main' of github.com:microsoft/CCF into node_cert_endors…
Aug 9, 2021
08f0ac0
Fix unit test
Aug 9, 2021
cbb41e0
Postpone frontend opening to hook
Aug 9, 2021
1f2adfa
Remove cert argument to Raft ctor
Aug 9, 2021
45fbb9c
Merge branch 'main' into node_cert_endorsement
jumaffre Aug 9, 2021
6075d50
Fix merge conflict
Aug 10, 2021
5ce7f52
Merge branch 'node_cert_endorsement' of github.com:jumaffre/CCF into …
Aug 10, 2021
b8e332b
Update constitution
Aug 10, 2021
5712eb8
Open frontend early if no endorsemen (fixes LTS)
Aug 10, 2021
6807334
.
Aug 11, 2021
b3a1883
..
Aug 11, 2021
de6aa15
WIP fix for BFT
Aug 12, 2021
566dcb5
Differentiate self signed from endorsed node cert
Aug 12, 2021
e7f9ed8
Merge branch 'main' of github.com:microsoft/CCF into node_cert_endors…
Aug 12, 2021
10577a7
Fix recovery
Aug 12, 2021
86b8091
Canary
Aug 12, 2021
33b00cf
Update changelog
Aug 12, 2021
4712e99
Update docs
Aug 12, 2021
0297c5f
fmt
Aug 12, 2021
b7b3046
Tweaks
Aug 12, 2021
16392d9
Fix UB
Aug 12, 2021
7a46548
Merge branch 'main' of github.com:microsoft/CCF into node_cert_endors…
Aug 13, 2021
20e4cfb
Merge branch 'main' of github.com:microsoft/CCF into node_cert_endors…
Aug 20, 2021
a1b0e01
Fix `node_frontent_test`
Aug 23, 2021
6aa3e88
WIP - where is certificate_subject_identity?
Aug 23, 2021
301837e
Remove certificate_subject_identity` field from governance
Aug 23, 2021
cf88f86
Merge branch 'main' into node_cert_endorsement
jumaffre Aug 23, 2021
7ad50e1
/Merge branch 'node_cert_endorsement' of github.com:jumaffre/CCF into…
Aug 23, 2021
e48584b
.
Aug 23, 2021
8fa9951
Fixes
Aug 23, 2021
86f108b
.
Aug 23, 2021
672cae8
Add valid_from and valid_to
Aug 24, 2021
f5a729c
Specify validity period in proposal
Aug 24, 2021
c746341
Check for time validity
Aug 25, 2021
0c9364b
Merge branch 'main' of github.com:microsoft/CCF into node_refresh_cer…
Aug 25, 2021
5ca652b
Better Python test
Aug 25, 2021
d5dda14
Check that validity period is reflected in node certificate
Aug 25, 2021
cb8570d
Pass maximum validity period from CLI
Aug 25, 2021
c619772
Update comment
Aug 26, 2021
407873c
More comprehensive e2e testing
Aug 26, 2021
ac8d484
.
Aug 26, 2021
d885f99
Merge branch 'main' of github.com:microsoft/CCF into node_refresh_cer…
Aug 27, 2021
644c053
Oops
Aug 27, 2021
3ecbf16
Merge branch 'main' of github.com:microsoft/CCF into node_refresh_cer…
Sep 10, 2021
9e56e91
Merge branch 'main' into node_refresh_cert_proposal
achamayou Sep 10, 2021
3b3b759
Merge branch 'main' into node_refresh_cert_proposal
achamayou Sep 11, 2021
1a79ef0
Merge branch 'main' of github.com:microsoft/CCF into node_refresh_cer…
Sep 27, 2021
bbed318
Merge branch 'node_refresh_cert_proposal' of github.com:jumaffre/CCF …
Sep 27, 2021
a9a27a2
Minor tweeks
Sep 27, 2021
adb3e68
Add ability to adjust time by a number of days
Sep 27, 2021
94c5891
Self-signed certificate uses time from host
Sep 28, 2021
f0c99c7
Use time from host as `valid_from`
Sep 28, 2021
7bb8173
.
Sep 29, 2021
0e2e6bc
Pass validity_period_days in proposal
Sep 30, 2021
09cd2ec
All tests work
Sep 30, 2021
122ea8d
Recovery too
Sep 30, 2021
9dc3e3d
.
Sep 30, 2021
6ac4701
Refactor certificate generation
Sep 30, 2021
f130861
Tweaks
Sep 30, 2021
b69cb1c
Use primary host time on join
Oct 1, 2021
c1f09b6
Global hook
Oct 1, 2021
52f0058
Rename node certificate renewal proposal action
Oct 1, 2021
0ce2f0d
Rename proposal
Oct 5, 2021
014d4bc
Rename cchost argument
Oct 5, 2021
60929a2
Add separate CLI argument for max allowed certificate validity period
Oct 5, 2021
8ba3d2f
Merge branch 'main' into node_refresh_cert_proposal
achamayou Oct 6, 2021
ad82b33
Merge branch 'main' of github.com:microsoft/CCF into node_refresh_cer…
Oct 14, 2021
5633a30
Merge branch 'node_refresh_cert_proposal' of github.com:jumaffre/CCF …
Oct 14, 2021
5947b80
Improve verification of node cert validity in e2e tests
Oct 14, 2021
ad69b0f
More tests are now passing
Oct 14, 2021
a70b856
Pass valid_from in transition_node_to_trusted proposal
Oct 15, 2021
be66f35
Sanitise certificate validity period early
Oct 15, 2021
51e6ea8
Verify validity period for service cert
Oct 15, 2021
19f4f17
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 18, 2021
01fd296
Fix node addition
Oct 18, 2021
3cdbb24
Merge branch 'node_refresh_cert_proposal' of github.com:jumaffre/CCF …
Oct 18, 2021
5e1a7fb
Recovery
Oct 18, 2021
d85971a
Enable more tests
Oct 18, 2021
a5e4b4d
Extract validity period from self-signed node certificate
Oct 18, 2021
cbd886c
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 18, 2021
a913e57
Tighten end-to-end test
Oct 18, 2021
b538bdd
Fix LTS test
Oct 18, 2021
5b55bd2
Fix governance test
Oct 19, 2021
15137a6
Check validity period in trust node proposal if it is set
Oct 19, 2021
af0ec7b
Add proposal to renew all certificates
Oct 19, 2021
6e796e4
Changelog
Oct 19, 2021
c5d4a1d
Docs
Oct 19, 2021
720aa04
Validity period is optional for all proposals
Oct 19, 2021
76efd6a
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 19, 2021
5876879
Return network object in test
Oct 20, 2021
648f9c5
Merge branch 'node_refresh_cert_proposal' of github.com:jumaffre/CCF …
Oct 20, 2021
5945d57
.
Oct 20, 2021
810c121
.
Oct 20, 2021
00d4470
Fix reconfiguration test
Oct 20, 2021
21ce7f3
Cycle nodes in lts compatibility
Oct 20, 2021
7f15f29
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 20, 2021
84c9d06
Add image
Oct 20, 2021
23d0582
Merge branch 'node_refresh_cert_proposal' of github.com:jumaffre/CCF …
Oct 20, 2021
47cba54
Fix lts ledger compatibility
Oct 20, 2021
1070ceb
mypy
Oct 20, 2021
56959b8
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 20, 2021
80485cd
Merge branch 'main' into node_refresh_cert_proposal
achamayou Oct 21, 2021
f7e66ff
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 25, 2021
4b2bfc6
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 26, 2021
a639da4
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 26, 2021
f0ef857
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 27, 2021
ebc3383
Merge branch 'main' into node_refresh_cert_proposal
achamayou Oct 27, 2021
2ce21b4
Merge branch 'main' into node_refresh_cert_proposal
jumaffre Oct 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .daily_canary
Original file line number Diff line number Diff line change
@@ -1 +1 @@
PSW!
.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `get_metrics_v1` API to `BaseEndpointRegistry` for applications that do not make use of builtins and want to version or customise metrics output.
- Slow ledger IO operations will now be logged at level FAIL. The threshold over which logging will activate can be adjusted by the `--io-logging-threshold` CLI argument to cchost (#3067).
- Snapshot files now include receipt of evidence transaction. Nodes can now join or recover a service from a standalone snapshot file. 2.x nodes can still make use of snapshots created by a 1.x node, as long as the ledger suffix containing the proof of evidence is also specified at start-up (#2998).
- Nodes certificates validity period is no longer hardcoded and can instead be set by operators and renewed by members (#2924):
- The new `--initial-node-cert-validity-days` (defaults to 1 day) CLI argument to cchost lets operators set the initial validity period for the node certificate (valid from the current system time).
- The new `--max-allowed-node-cert-validity-days` (defaults to 365 days) CLI argument to cchost sets the maximum validity period allowed for node certificates.
- The new `set_node_certificate_validity` proposal action allows members to renew a node certificate (or `set_all_nodes_certificate_validity` equivalent action to renew _all_ trusted nodes certificates).
- The existing `transition_node_to_trusted` proposal action now requires a new `valid_from` argument (and optional `validity_period_days`, which defaults to the value of ``--max-allowed-node-cert-validity-days`).
- `ccf.historical.getStateRange` / `ccf.historical.dropCachedStates` JavaScript APIs to manually retrieve historical state in endpoints declared as `"mode": "readonly"` (#3033).

### Changed
Expand Down
31 changes: 30 additions & 1 deletion doc/governance/common_member_operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,33 @@ The number of member shares required to restore the private ledger (``recovery_t
"state": "Accepted"
}

.. note:: The new recovery threshold has to be in the range between 1 and the current number of active recovery members.
.. note:: The new recovery threshold has to be in the range between 1 and the current number of active recovery members.

Renewing Node Certificate
-------------------------

.. note:: Renewing the certificate of a node does not change the identity (public key) of that node but only its validity period.

To renew the soon-to-be-expired certificate of a node, members should issue a ``set_node_certificate_validity`` proposal, specifying the date at which the validity period of the renewed certificate should start (``valid_from``), as well as its validity period in days (``validity_period_days``).

The ``valid_from`` date argument should be a ASN1 UTCTime string, i.e. ``"YYMMDDhhmmssZ"``. The ``validity_period_days`` should be less than the validity period set by operators (see :ref:`operations/certificates:Node Certificates`).

A sample proposal is:

.. code-block:: bash

$ cat set_node_certificate_validity.json
{
"actions": [
{
"name": "set_node_certificate_validity",
"args": {
"node_id": "86c0ccfab4b869abbc779937c51158c9dd2a130d58323643a3119e83b33dcf5c"
"valid_from": "211019154318Z",
"validity_period_days": 365
}
}
]
}

.. tip:: All currently trusted nodes certificates can be renewed at once using the ``set_all_nodes_certificate_validity`` proposal (same arguments minus ``node_id``).
4 changes: 2 additions & 2 deletions doc/governance/proposals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ Some of these subcommands require additional arguments, such as the node ID or u

.. code-block:: bash

$ python -m ccf.proposal_generator transition_node_to_trusted 6d566123a899afaea977c5fc0f7a2a9fef33f2946fbc4abefbc3e10ee597343f
$ python -m ccf.proposal_generator transition_node_to_trusted 6d566123a899afaea977c5fc0f7a2a9fef33f2946fbc4abefbc3e10ee597343f 211019154318Z
SUCCESS | Writing proposal to ./trust_node_proposal.json
SUCCESS | Wrote vote to ./trust_node_vote_for.json

$ cat trust_node_proposal.json
{"actions": [{"name": "transition_node_to_trusted", "args": {"node_id": "6d566123a899afaea977c5fc0f7a2a9fef33f2946fbc4abefbc3e10ee597343f"}}]}
{"actions": [{"name": "transition_node_to_trusted", "args": {"node_id": "6d566123a899afaea977c5fc0f7a2a9fef33f2946fbc4abefbc3e10ee597343f", "valid_from": "211019154318Z"}}]}

$ python -m ccf.proposal_generator --pretty-print --proposal-output-file add_pedro.json --vote-output-file vote_for_pedro.json set_user pedro_cert.pem
SUCCESS | Writing proposal to ./add_pedro.json
Expand Down
15 changes: 15 additions & 0 deletions doc/operations/certificates.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Certificates
============

Since 2.x releases, the validity period of certificates is no longer hardcoded. This page describes how the validity period can instead be set by operators, and renewed by members.

.. note:: The granularity for the validity period of nodes certificates is one day.

Node Certificates
-----------------

At startup, operators can set the validity period for a node using the ``--initial-node-cert-validity-days`` CLI argument. The default value is set to 1 day and it is expected that members will issue a proposal to renew the certificate before it expires, when the service is open. Initial nodes certificates are valid from the current system time when the ``cchost`` executable is launched.

The ``--max-allowed-node-cert-validity-days`` CLI argument (defaults to 365 days) can be used to set the maximum allowed validity period for nodes certificates when they are renewed by members. It is used as the default value for the validity period when a node certificate is renewed but the validity period is omitted.

.. tip:: Once a node certificate has expired, clients will no longer trust the node serving their request. It is expected that operators and members will monitor the certificate validity dates with regards to current time and renew the node certificate before expiration. See :ref:`governance/common_member_operations:Renewing Node Certificate` for more details.
7 changes: 7 additions & 0 deletions doc/operations/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ This section describes how :term:`Operators` manage the different nodes constitu

---

:fa:`stamp` :doc:`certificates`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Set and renew nodes and service x509 certificates.

---

:fa:`helicopter` :doc:`recovery`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
1 change: 0 additions & 1 deletion include/ccf/endpoint_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "ds/json_schema.h"
#include "ds/openapi.h"
#include "http/http_consts.h"
#include "node/certs.h"
#include "node/endpoint_metrics.h"
#include "node/rpc/serialization.h"

Expand Down
29 changes: 27 additions & 2 deletions python/ccf/proposal_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,13 @@ def refresh_js_app_bytecode_cache(**kwargs):


@cli_proposal
def transition_node_to_trusted(node_id: str, **kwargs):
return build_proposal("transition_node_to_trusted", {"node_id": node_id}, **kwargs)
def transition_node_to_trusted(
node_id: str, valid_from: str, validity_period_days: Optional[int] = None, **kwargs
):
args = {"node_id": node_id, "valid_from": valid_from}
if validity_period_days is not None:
args["validity_period_days"] = validity_period_days
return build_proposal("transition_node_to_trusted", args, **kwargs)


@cli_proposal
Expand Down Expand Up @@ -325,6 +330,26 @@ def set_jwt_public_signing_keys(issuer: str, jwks_path: str, **kwargs):
return build_proposal("set_jwt_public_signing_keys", args, **kwargs)


@cli_proposal
def set_node_certificate_validity(
node_id: str, valid_from: str, validity_period_days: Optional[int] = None, **kwargs
):
args = {"node_id": node_id, "valid_from": valid_from}
if validity_period_days is not None:
args["validity_period_days"] = validity_period_days
return build_proposal("set_node_certificate_validity", args, **kwargs)


@cli_proposal
def set_all_nodes_certificate_validity(
valid_from: str, validity_period_days: Optional[int] = None, **kwargs
):
args = {"valid_from": valid_from}
if validity_period_days is not None:
args["validity_period_days"] = validity_period_days
return build_proposal("set_all_nodes_certificate_validity", args, **kwargs)


if __name__ == "__main__":
parser = argparse.ArgumentParser()

Expand Down
76 changes: 76 additions & 0 deletions src/crypto/certs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once

#include "key_pair.h"
#include "openssl/x509_time.h"
#include "pem.h"

#include <string>

namespace crypto
{
static std::string compute_cert_valid_to_string(
const std::string& valid_from, size_t validity_period_days)
{
// Note: As per RFC 5280, the validity period runs until "notAfter"
// _inclusive_ so substract one second from the validity period.
auto valid_to = OpenSSL::adjust_time(valid_from, validity_period_days, -1);
return OpenSSL::to_x509_time_string(OpenSSL::to_time_t(valid_to));
}

static Pem create_self_signed_cert(
const KeyPairPtr& key_pair,
const CertificateSubjectIdentity& csi,
const std::string& valid_from,
size_t validity_period_days)
{
return key_pair->self_sign(
csi,
true /* CA */,
valid_from,
compute_cert_valid_to_string(valid_from, validity_period_days));
}

static Pem create_endorsed_cert(
const Pem& csr,
const std::string& valid_from,
const std::string& valid_to,
const Pem& issuer_key_pair,
const Pem& issuer_cert)
{
return make_key_pair(issuer_key_pair)
->sign_csr(issuer_cert, csr, false /* Not CA */, valid_from, valid_to);
}

static Pem create_endorsed_cert(
const Pem& csr,
const std::string& valid_from,
size_t validity_period_days,
const Pem& issuer_key_pair,
const Pem& issuer_cert)
{
return create_endorsed_cert(
csr,
valid_from,
compute_cert_valid_to_string(valid_from, validity_period_days),
issuer_key_pair,
issuer_cert);
}

static Pem create_endorsed_cert(
const KeyPairPtr& subject_key_pair,
const CertificateSubjectIdentity& csi,
const std::string& valid_from,
size_t validity_period_days,
const Pem& issuer_key_pair,
const Pem& issuer_cert)
{
return create_endorsed_cert(
subject_key_pair->create_csr(csi),
valid_from,
validity_period_days,
issuer_key_pair,
issuer_cert);
}
}
18 changes: 13 additions & 5 deletions src/crypto/key_pair.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,32 @@ namespace crypto
virtual Pem sign_csr(
const Pem& issuer_cert,
const Pem& signing_request,
bool ca = false) const = 0;
bool ca = false,
const std::optional<std::string>& valid_from = std::nullopt,
const std::optional<std::string>& valid_to = std::nullopt) const = 0;

Pem self_sign(
const std::string& name,
const std::optional<SubjectAltName> subject_alt_name = std::nullopt,
bool ca = true) const
bool ca = true,
const std::optional<std::string>& valid_from = std::nullopt,
const std::optional<std::string>& valid_to = std::nullopt) const
{
std::vector<SubjectAltName> sans;
if (subject_alt_name.has_value())
sans.push_back(subject_alt_name.value());
auto csr = create_csr({name, sans});
return sign_csr(Pem(0), csr, ca);
return sign_csr(Pem(0), csr, ca, valid_from, valid_to);
}

Pem self_sign(const CertificateSubjectIdentity& csi, bool ca = true) const
Pem self_sign(
const CertificateSubjectIdentity& csi,
bool ca = true,
const std::optional<std::string>& valid_from = std::nullopt,
const std::optional<std::string>& valid_to = std::nullopt) const
{
auto csr = create_csr(csi);
return sign_csr(Pem(0), csr, ca);
return sign_csr(Pem(0), csr, ca, valid_from, valid_to);
}
};

Expand Down
13 changes: 11 additions & 2 deletions src/crypto/mbedtls/key_pair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,11 @@ namespace crypto
}

Pem KeyPair_mbedTLS::sign_csr(
const Pem& issuer_cert, const Pem& signing_request, bool ca) const
const Pem& issuer_cert,
const Pem& signing_request,
bool ca,
const std::optional<std::string>& valid_from,
const std::optional<std::string>& valid_to) const
{
auto entropy = create_entropy();
auto csr = mbedtls::make_unique<mbedtls::X509Csr>();
Expand Down Expand Up @@ -321,8 +325,13 @@ namespace crypto

// Note: 825-day validity range
// https://support.apple.com/en-us/HT210176
// Note: For the mbedtls implementation, we do not check that valid_from and
// valid_to are valid or chronological. See OpenSSL equivalent call for a
// safer implementation.
MCHK(mbedtls_x509write_crt_set_validity(
crt.get(), "20210311000000", "20230611235959"));
crt.get(),
valid_from.value_or("20210311000000").c_str(),
valid_to.value_or("20230611235959").c_str()));

MCHK(mbedtls_x509write_crt_set_basic_constraints(crt.get(), ca ? 1 : 0, 0));
MCHK(mbedtls_x509write_crt_set_subject_key_identifier(crt.get()));
Expand Down
4 changes: 3 additions & 1 deletion src/crypto/mbedtls/key_pair.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ namespace crypto
virtual Pem sign_csr(
const Pem& issuer_cert,
const Pem& signing_request,
bool ca = false) const override;
bool ca = false,
const std::optional<std::string>& valid_from = std::nullopt,
const std::optional<std::string>& valid_to = std::nullopt) const override;
};
}
20 changes: 20 additions & 0 deletions src/crypto/mbedtls/verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ namespace crypto
"-----BEGIN CERTIFICATE-----\n";
static constexpr auto PEM_CERTIFICATE_FOOTER = "-----END CERTIFICATE-----\n";

static inline std::string to_x509_time_string(const mbedtls_x509_time& time)
{
// Returns ASN1 time string (YYYYMMDDHHMMSSZ)
return fmt::format(
"{:02}{:02}{:02}{:02}{:02}{:02}Z",
time.year,
time.mon,
time.day,
time.hour,
time.min,
time.sec);
}

MDType Verifier_mbedTLS::get_md_type(mbedtls_md_type_t mdt) const
{
switch (mdt)
Expand Down Expand Up @@ -196,4 +209,11 @@ namespace crypto
}
return buf;
}

std::pair<std::string, std::string> Verifier_mbedTLS::validity_period() const
{
return std::make_pair(
to_x509_time_string(cert->valid_from),
to_x509_time_string(cert->valid_to));
}
}
3 changes: 3 additions & 0 deletions src/crypto/mbedtls/verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ namespace crypto
virtual bool is_self_signed() const override;

virtual std::string serial_number() const override;

virtual std::pair<std::string, std::string> validity_period()
const override;
};
}
31 changes: 19 additions & 12 deletions src/crypto/openssl/key_pair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "crypto/openssl/public_key.h"
#include "hash.h"
#include "openssl_wrappers.h"
#include "x509_time.h"

#define FMT_HEADER_ONLY
#include <fmt/format.h>
Expand Down Expand Up @@ -215,7 +216,11 @@ namespace crypto
}

Pem KeyPair_OpenSSL::sign_csr(
const Pem& issuer_cert, const Pem& signing_request, bool ca) const
const Pem& issuer_cert,
const Pem& signing_request,
bool ca,
const std::optional<std::string>& valid_from,
const std::optional<std::string>& valid_to) const
{
X509* icrt = NULL;
Unique_BIO mem(signing_request);
Expand Down Expand Up @@ -256,17 +261,19 @@ namespace crypto

// Note: 825-day validity range
// https://support.apple.com/en-us/HT210176
ASN1_TIME *before = NULL, *after = NULL;
OpenSSL::CHECKNULL(before = ASN1_TIME_new());
OpenSSL::CHECKNULL(after = ASN1_TIME_new());
OpenSSL::CHECK1(ASN1_TIME_set_string(before, "20210311000000Z"));
OpenSSL::CHECK1(ASN1_TIME_set_string(after, "20230611235959Z"));
OpenSSL::CHECK1(ASN1_TIME_normalize(before));
OpenSSL::CHECK1(ASN1_TIME_normalize(after));
OpenSSL::CHECK1(X509_set1_notBefore(crt, before));
OpenSSL::CHECK1(X509_set1_notAfter(crt, after));
ASN1_TIME_free(before);
ASN1_TIME_free(after);
Unique_X509_TIME not_before(valid_from.value_or("20210311000000Z"));
jumaffre marked this conversation as resolved.
Show resolved Hide resolved
Unique_X509_TIME not_after(valid_to.value_or("20230611235959Z"));
if (!validate_chronological_times(not_before, not_after))
{
throw std::logic_error(fmt::format(
"Certificate cannot be created with not_before date {} > not_after "
"date {}",
to_x509_time_string(not_before),
to_x509_time_string(not_after)));
}

OpenSSL::CHECK1(X509_set1_notBefore(crt, not_before));
OpenSSL::CHECK1(X509_set1_notAfter(crt, not_after));

X509_set_subject_name(crt, X509_REQ_get_subject_name(csr));
X509_set_pubkey(crt, req_pubkey);
Expand Down
Loading