SERVER-101468 Update certificate generation to be cross-platform and deterministic (#33814)

GitOrigin-RevId: 3ef1af57ac423e448ee1a7d7d9a21a6fad0ae79f
This commit is contained in:
Gabriel Marks 2025-03-26 20:23:45 +00:00 committed by MongoDB Bot
parent 8febf85a4b
commit 8a719210c5
38 changed files with 2738 additions and 1 deletions

3
.github/CODEOWNERS vendored
View File

@ -2636,3 +2636,6 @@ WORKSPACE.bazel @10gen/devprod-build @svc-auto-approve-bot
# The following patterns are parsed from ./src/third_party/libmongocrypt/OWNERS.yml
/src/third_party/libmongocrypt/**/* @10gen/server-security @svc-auto-approve-bot
# The following patterns are parsed from ./x509/OWNERS.yml
/x509/**/* @10gen/server-security @svc-auto-approve-bot

View File

@ -222,6 +222,7 @@ tasks:
- "src/src/third_party/schemastore.org/**"
- "src/poetry.lock"
- "src/pyproject.toml"
- "src/x509/**"
exclude_files:
- "src/*_test.pdb"

View File

@ -0,0 +1,13 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")
js_library(
name = "all_javascript_files",
srcs = glob([
"*.js",
]),
target_compatible_with = select({
"//bazel/config:ppc_or_s390x": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,52 @@
// Test that mkcert.py generates certificates deterministically, and that pkcs12 certificates, while
// not deterministic, can be generated.
import {getPython3Binary} from "jstests/libs/python.js";
const now = new Date();
// Note - month is 0-indexed, so 11 is December.
if (now.getMonth() == 11 && now.getDate() == 31 && now.getHours() == 23) {
jsTestLog(
"Deterministic certificate generation relies on the current year being constant; skipping test as there is less than an hour until the year changes.");
quit();
}
// Print the openssl version to help with debugging.
clearRawMongoProgramOutput();
assert.eq(runNonMongoProgram("openssl", "version"), 0);
jsTest.log(rawMongoProgramOutput(".*"));
const basedir = MongoRunner.dataPath + "certs/";
const genpath = basedir + "generated/";
mkdir(genpath);
// Run mkcert, and ensure it succeeds and that expected results are generated successfully.
jsTest.log("Running mkcert");
clearRawMongoProgramOutput();
let res = runNonMongoProgram(getPython3Binary(), "-m", "x509.mkcert", "--mkcrl", "-o", genpath);
jsTest.log(rawMongoProgramOutput(".*"));
assert.eq(res, 0);
assert(fileExists(genpath + "ca.pem"));
assert(fileExists(genpath + "crl.pem"));
// Run mkcert again, to a different path.
const genpath2 = basedir + "generated2/";
mkdir(genpath2);
jsTest.log("Running mkcert again");
res = runNonMongoProgram(getPython3Binary(), "-m", "x509.mkcert", "--mkcrl", "-o", genpath2);
assert.eq(res, 0);
// Diff the two generation paths to make sure the contents of the paths are identical.
jsTest.log("Running diff");
clearRawMongoProgramOutput();
res = runNonMongoProgram("diff", "-r", genpath, genpath2);
assert.eq(res, 0);
const diffout = rawMongoProgramOutput(".*").trim();
assert.eq("", diffout, diffout);
// Run mkcert on the apple-certs.yml definitions file, which contains pkcs12 certificates, and
// ensure a .pfx file was generated.
jsTest.log("Running apple certs");
res = runNonMongoProgram(
getPython3Binary(), "-m", "x509.mkcert", "-o", genpath, "--config", "x509/apple-certs.yml");
assert.eq(res, 0);
assert(fileExists(genpath + "macos-trusted-server.pfx"));

22
poetry.lock generated
View File

@ -830,6 +830,26 @@ https = ["urllib3 (>=1.24.1)"]
paramiko = ["paramiko"]
pgp = ["gpg"]
[[package]]
name = "ecdsa"
version = "0.19.0"
description = "ECDSA cryptographic signature library (pure python)"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6"
groups = ["testing"]
markers = "platform_machine != \"s390x\" and platform_machine != \"ppc64le\" or platform_machine == \"s390x\" or platform_machine == \"ppc64le\""
files = [
{file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"},
{file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"},
]
[package.dependencies]
six = ">=1.9.0"
[package.extras]
gmpy = ["gmpy"]
gmpy2 = ["gmpy2"]
[[package]]
name = "enum-compat"
version = "0.0.3"
@ -5267,4 +5287,4 @@ libdeps = ["cxxfilt", "eventlet", "flask", "flask-cors", "gevent", "lxml", "prog
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<4.0"
content-hash = "2f5d3d54b6f487fda3636bb4b7214c82dfe73ce204b673d8bbde467d23f325fb"
content-hash = "6d15c0ce1d7ae43732d67e09401d01bd0dab74edf9f8a98c670f60112a5f68c6"

View File

@ -145,6 +145,8 @@ shrub-py = "^3.1.4"
ocspresponder = "^0.5.0"
flask = "^2.3.3"
ocspbuilder = "^0.10.2"
ecdsa = "^0.19.0"
asn1crypto = "^1.5.1"
toml = ">=0.10.2,<0.11.0"
# Werkzeug is needed for ocsp tests in ocsp_mock.py

5
x509/OWNERS.yml Normal file
View File

@ -0,0 +1,5 @@
version: 1.0.0
filters:
- "*":
approvers:
- 10gen/server-security

93
x509/README Normal file
View File

@ -0,0 +1,93 @@
This directory contains:
- mkcert.py
Python script; uses the cryptography package to deterministically generate X509 certificates,
CRLs, and digests based on the contents of certs.yml.
- certs.yml
Main certificate definition file.
- apple-certs.yml
Certificate definitions for certs to be installed on provision of OSX machines.
To run:
python -m x509.mkcert [--config CONFIG] [--mkcrl | --no-mkcrl] [-o OUTPUT] [--static-dir STATIC_DIR] [certs ...]
- CONFIG is the path to the certs.yml file specifying a list of certificates, default x509/certs.yml
- OUTPUT is the path to a directory where the generated items will be stored, default .
- STATIC_DIR is the path where signing keys needed by certificates are stored, default x509/static
- If --mkcrl is specified, CRLs will be generated after certificate generation ends. Default false.
These are hardcoded and require certain certificates to be generated to work.
- certs is an optional list of certificate names to generate. If it is not specified, all
certificates specified in the config are generated.
If a certificate specified in certs references other certificates, its dependencies and
subdependencies will be generated.
Deterministic generation is based on the current year. This means that if mkcert is run on the same
definitions file twice, it will produce the same certificates if both runs were in the same year.
One exception to this is the pkcs12 format; the cryptography library does not provide
functionality for generating pkcs12 bundles deterministically.
Future work:
- Define CRLs in the definition file instead of hardcoding them.
- Define keys in the definition file, and make a script to generate all necessary keys which would
be run whenever a new key was defined.
certs.yml format:
global: # Optional, default value to use for Key1 for all certs, overridden by values in cert entries.
Key1: Value1
...
certs:
# Required, this will be used as the name of the file, and for referencing issuers.
- name: 'name-of-cert.pem'
# Required, this will be included in the header of the generated certificate.
description: Tell us about yourself.
# Required, The X509 subject name.
Subject: { C: US, ST: New York, etc... }
# Required, Who is the (intermediate) CA for this certificate. May be 'self'.
Issuer: 'ca.pem'
# Required, relative (within static directory) path to the keyfile to sign this certificate with.
keyfile: 'key.pem'
# Optional, set to true to ignore global.Subject values.
explicit_subject: false
# Optional, serial number to assign this certificate (default: sequential numbers starting from 1000)
serial: 42
# Optional, validity start date, expressed in seconds relative to midnight on the first day of the current year.
not_before: -86400 # 1 day before
# Optional, validity end date, currently expressed in seconds relative to midnight on the first day of the current year.
# Note that not_after - not_before, the validity period, should be less than or equal to 825 days, see:
# https://support.apple.com/en-us/HT210176
not_after: 71107200 # 823 days after
# Optional, IDs of other public keys to append to the file
append_certs: ['ca.pem', 'intermediate-ca.pem', ...]
# Optional, passphrase to encript private key with
passphrase: 'secret'
# Optional, make a pkcs12 copy of the certificate
pkcs12: true | map with keys below
# Optional, all PKCS#12 keys must be encrypted. Will use cert.passphase if not provided.
passphrase: 'secret'
# Optional, name of PKCS#12 version of certificate. If not provided, the original cert will be overwritten with the PKCS#12 version
name: 'name-of-cert.pfx'
# Optional, in addition to the .pem file, write just the certificate to a .crt file and just the signing key to a .key file
split_cert_and_key: true
# Optional, don't write a header comment to this cert
include_header: false
# Optional, X.509 extensions to include in the certificate
extensions: # All extensions are optional.
- basicConstraints: {}
- keyUsage: {}
- extendedKeyUsage: {}
- subjectAltName: {DNS: [...], IP: [...]}
- subjectKeyIdentifier: hash
- authorityKeyIdentifier: keyid | issuer
- authorityInfoAccess:
- method: OCSP
- location: uri-to-OCSP-server
- mustStaple: true
- nsComment: "Comment"
- mongoRoles:
- {role: readWrite, db: test1}
- {role: read, db: test2}
- mongoClusterMembership: clusterName

0
x509/__init__.py Normal file
View File

49
x509/apple-certs.yml Normal file
View File

@ -0,0 +1,49 @@
# Definition for testing certificates to be created and installed into the MacOS trusted keychain upon provision.
# On MacOS provision, these certificates will be written to /opt/x509.
global:
Subject:
C: "US"
ST: "New York"
L: "New York City"
O: "MongoDB"
OU: "Kernel"
keyfile: "macos_key.pem"
certs:
- name: "macos-trusted-ca.pem"
description: CA for trusted MacOS client/server certificate chain.
Subject: {CN: "Trusted MacOS Kernel Test CA"}
Issuer: self
keyfile: "macos_ca_key.pem"
extensions:
basicConstraints: {CA: true}
subjectAltName:
DNS: localhost
IP: 127.0.0.1
- name: "macos-trusted-client.pem"
description: Client certificate for trusted MacOS chain.
Subject: {CN: "Trusted MacOS Kernel Test Client"}
Issuer: "macos-trusted-ca.pem"
pkcs12:
passphrase: "qwerty"
name: "macos-trusted-client.pfx"
extensions:
extendedKeyUsage: [clientAuth]
subjectAltName:
DNS: localhost
IP: 127.0.0.1
- name: "macos-trusted-server.pem"
description: Server certificate for trusted MacOS chain.
Subject: {CN: "Trusted MacOS Kernel Test Server"}
Issuer: "macos-trusted-ca.pem"
pkcs12:
passphrase: "qwerty"
name: "macos-trusted-server.pfx"
extensions:
extendedKeyUsage: [serverAuth]
subjectAltName:
DNS: localhost
IP: 127.0.0.1

1076
x509/certs.yml Normal file

File diff suppressed because it is too large Load Diff

817
x509/mkcert.py Normal file
View File

@ -0,0 +1,817 @@
# Script which deterministically generates certificates given a definitions file.
import argparse
import datetime
import hashlib
import ipaddress
from pathlib import PurePath
from typing import Any, Dict
import asn1crypto.core as asn1
import cryptography.hazmat.primitives.serialization.pkcs12 as pkcs12
import yaml
from cryptography import x509
from cryptography.hazmat._oid import _OID_NAMES
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.x509.extensions import UnrecognizedExtension
from cryptography.x509.oid import ObjectIdentifier
from ecdsa import SigningKey
# Dictionary from common names to OIDs.
NAME_TO_OID = {v: k for k, v in _OID_NAMES.items()}
# Map short names that we explicitly support to their corresponding OIDs.
NAME_TO_OID["C"] = NAME_TO_OID["countryName"]
NAME_TO_OID["ST"] = NAME_TO_OID["stateOrProvinceName"]
NAME_TO_OID["O"] = NAME_TO_OID["organizationName"]
NAME_TO_OID["OU"] = NAME_TO_OID["organizationalUnitName"]
NAME_TO_OID["L"] = NAME_TO_OID["localityName"]
NAME_TO_OID["SN"] = NAME_TO_OID["surname"]
NAME_TO_OID["CN"] = NAME_TO_OID["commonName"]
# Path to the file specifying the config.
CONFIGFILE = None
# Config parsed as YAML.
CONFIG = Dict[str, Any]
# <= 825 in order to abide by https://support.apple.com/en-us/HT210176.
MAX_VALIDITY_PERIOD_DAYS = 824
# Datetime to specify as the start time for all certs.
# TODO SERVER-101469 Make this a command-line argument and add it as a Bazel input so that Bazel
# knows when to rerun certificate generation.
DEFAULT_START_TIME = datetime.datetime(datetime.datetime.now().year, 1, 1)
# Allocate serial numbers sequentially; this is the last-used serial.
LAST_SERIAL_NUMBER = 999
# Cache the private key objects for static/*key.pem.
LOADED_KEYS = {}
# Base directory where outputs go.
OUTPUT_PATH = None
# Base path to keys that are used during generation.
STATIC_PATH = None
LOADED_CERT_AND_KEYS = {}
def get_next_serial():
"""Get the next sequential serial number to use."""
global LAST_SERIAL_NUMBER
# Serial numbers 0..999 are reserved for fixed serial numbers.
# Start at 1000 and increment every time we generate a cert.
LAST_SERIAL_NUMBER += 1
return LAST_SERIAL_NUMBER
def get_key(cert):
"""Get the private key object loaded from keyfile."""
keyfile = idx(cert, "keyfile")
if keyfile is None:
raise ValueError("All certificates require a keyfile")
if keyfile not in LOADED_KEYS:
passphrase = cert.get("passphrase")
if passphrase is not None:
passphrase = bytes(passphrase, "ascii")
with open(str(STATIC_PATH / keyfile), "rb") as f:
LOADED_KEYS[keyfile] = serialization.load_pem_private_key(
f.read(),
password=passphrase,
)
return LOADED_KEYS[keyfile]
def glbl(key, default=None):
"""Fetch a key from the global dict."""
return CONFIG.get("global", {}).get(key, default)
def idx(cert, key, default=None):
"""Fetch a key from the cert dict, falling back through global dict."""
return cert.get(key, None) or glbl(key, default)
def make_filename(cert):
"""Form a pathname from a certificate definition."""
return str(OUTPUT_PATH / cert["name"])
def find_certificate_definition(name):
"""Locate a definition by name."""
for ca_cert in CONFIG["certs"]:
if ca_cert["name"] == name:
return ca_cert
return None
def get_header_comment(cert):
"""Get the correct header comment for the certificate."""
if not cert.get("include_header", True):
return ""
"""Header comment for every generated file."""
comment = "# Autogenerated file, do not edit.\n"
comment = comment + "# Generate using python -m x509.mkcert --config " + CONFIGFILE
comment = comment + " " + cert["name"] + "\n#\n"
comment = comment + "# " + cert.get("description", "").replace("\n", "\n# ")
comment = comment + "\n"
return comment
def get_cert_and_key(cert_name):
"""Locate the cert and key file for a given cert name, load them, and return them."""
if cert_name in LOADED_CERT_AND_KEYS: # Cache hit, don't need to load again
return LOADED_CERT_AND_KEYS[cert_name]
ca_cert = find_certificate_definition(cert_name)
if ca_cert:
with open(make_filename(ca_cert), "rb") as f:
pem = f.read()
certificate = x509.load_pem_x509_certificate(pem)
passphrase = ca_cert.get("passphrase", None)
if passphrase:
passphrase = passphrase.encode("utf-8")
key = serialization.load_pem_private_key(
pem,
password=passphrase,
)
LOADED_CERT_AND_KEYS[cert_name] = (certificate, key)
return (certificate, key)
# Externally sourced certifiate, try by path. Hopefully unencrypted.
with open(cert_name, "rb") as f:
pem = f.read()
certificate = x509.load_pem_x509_certificate(pem)
key = serialization.load_pem_private_key(pem, password=None)
LOADED_CERT_AND_KEYS[cert_name] = (certificate, key)
return (certificate, key)
def get_validity_period(cert):
"""Get the validity range for the certificate."""
start_shift_secs = int(idx(cert, "not_before", 0))
end_shift_secs = int(
idx(cert, "not_after", start_shift_secs + MAX_VALIDITY_PERIOD_DAYS * 24 * 60 * 60)
)
start_time = DEFAULT_START_TIME + datetime.timedelta(seconds=start_shift_secs)
end_time = DEFAULT_START_TIME + datetime.timedelta(seconds=end_shift_secs)
return start_time, end_time
def get_oid(cn_or_oid):
"""Given a string containing an OID or a common name, return the corresponding OID object."""
if cn_or_oid in NAME_TO_OID:
return NAME_TO_OID[cn_or_oid]
try:
return ObjectIdentifier(cn_or_oid)
except:
raise ValueError(f"Name attribute {cn_or_oid} not recognized")
def set_subject(builder, cert, set_issuer=False):
"""Set the subject on the certificate builder according to the certificate definition. Also set the issuer to the same thing if set_issuer is true."""
if not cert.get("Subject"):
if cert.get("explicit_subject", False):
# do nothing if an empty subject is explicitly provided
if set_issuer:
builder = builder.issuer_name(x509.Name([]))
return builder.subject_name(x509.Name([]))
raise ValueError(cert["name"] + " requires a Subject")
attr_dict = {}
if not cert.get("explicit_subject", False):
# Load the globally defined subject RDNs
for key, val in glbl("Subject", {}).items():
oid = get_oid(key)
attr_dict[oid] = val
if isinstance(cert["Subject"], dict):
# Normal case: Load the subject RDNs defined by the certificate over the globally defined ones
for key, val in cert["Subject"].items():
oid = get_oid(key)
attr_dict[oid] = val
name = x509.Name([x509.NameAttribute(key, val) for key, val in attr_dict.items()])
else:
# Multivalued RDN case
assert isinstance(cert["Subject"], list)
assert cert[
"explicit_subject"
], "explicit_subject must be set to true when using multivalued RDNs"
rdns = []
for rdn_def in cert["Subject"]:
attrs = []
for key, val in rdn_def.items():
oid = get_oid(key)
attrs.append(x509.NameAttribute(oid, val))
rdns.append(x509.RelativeDistinguishedName(attrs))
name = x509.Name(rdns)
if set_issuer: # When issuer = self, set the issuer as well
builder = builder.issuer_name(name)
return builder.subject_name(name)
def set_validity(builder, cert):
"""Set the not_valid_before/after fields on the certificate builder according to the certificate definition."""
start, end = get_validity_period(cert)
builder = builder.not_valid_before(start)
return builder.not_valid_after(end)
def to_der_varint(val):
"""Translate a native int to a variable length ASN.1 encoded integer."""
if val < 0:
raise ValueError("Negative values nor permitted in DER payload")
if val < 0x80:
return chr(val).encode("ascii")
ret = bytearray(b"")
while (val > 0) and (len(ret) < 8):
ret.insert(0, val & 0xFF)
val = val >> 8
if val > 0:
raise ValueError("Length is too large to represent in 64bits")
ret.insert(0, 0x80 + len(ret))
return ret
def to_der_utf8_string(val):
"""Encode a unicode string as a ASN.1 UTF8 String."""
utf8_val = str(val).encode("utf-8")
return b"\x0c" + to_der_varint(len(utf8_val)) + utf8_val
def to_der_sequence_pair(name, value):
"""Encode a pair of ASN.1 values as a sequence pair."""
# Simplified sequence which always expects two string, a key and a value.
bin_name = to_der_utf8_string(name)
bin_value = to_der_utf8_string(value)
return b"\x30" + to_der_varint(len(bin_name) + len(bin_value)) + bin_name + bin_value
class ExtensionParser:
"""Collection of methods to convert extension definitions into cryptography extension objects."""
@staticmethod
def basic_constraints(v, **_):
return x509.BasicConstraints(ca=v.get("CA", False), path_length=v.get("pathlen"))
@staticmethod
def key_usage(v, **_):
to_param_name = {
"digitalSignature": "digital_signature",
"nonRepudiation": "content_commitment",
"keyEncipherment": "key_encipherment",
"dataEncipherment": "data_encipherment",
"keyAgreement": "key_agreement",
"keyCertSign": "key_cert_sign",
"cRLSign": "crl_sign",
"encipherOnly": "encipher_only",
"decipherOnly": "decipher_only",
}
params = {name: False for name in to_param_name.values()}
for usage in v:
if usage in to_param_name:
params[to_param_name[usage]] = True
return x509.KeyUsage(**params)
@staticmethod
def ext_usage_name_to_oid(name):
ext_usage_name_map = {
"serverAuth": 1,
"clientAuth": 2,
"codeSigning": 3,
"emailProtection": 4,
"timeStamping": 8,
"OCSPSigning": 9,
}
if name not in ext_usage_name_map:
raise ValueError(f'Unknown extended key usage identifier: "{name}"')
return ObjectIdentifier("1.3.6.1.5.5.7.3." + str(ext_usage_name_map[name]))
@staticmethod
def extended_key_usage(v, **_):
return x509.ExtendedKeyUsage([ExtensionParser.ext_usage_name_to_oid(name) for name in v])
@staticmethod
def subject_alt_name(v, **_):
names = []
for key, val in v.items():
if key == "critical":
continue
elif key == "DNS":
if not isinstance(val, list):
val = [val]
for name in val:
names.append(x509.DNSName(name))
elif key == "IP":
if not isinstance(val, list):
val = [val]
for ip in val:
names.append(x509.IPAddress(ipaddress.ip_address(ip)))
else:
raise ValueError(f'Unknown subject alt name type: "{key}"')
return x509.SubjectAlternativeName(names)
@staticmethod
def subject_key_identifier(v, public_key, **_):
assert v == "hash"
return x509.SubjectKeyIdentifier.from_public_key(public_key)
@staticmethod
def mongo_roles(v, **_):
oid = ObjectIdentifier("1.3.6.1.4.1.34601.2.1.1")
pair = b""
for role in v:
if (len(role) != 2) or ("role" not in role) or ("db" not in role):
raise ValueError("mongoRoles must consist of a series of role/db pairs")
pair = pair + to_der_sequence_pair(role["role"], role["db"])
val = b"\x31" + to_der_varint(len(pair)) + pair
return UnrecognizedExtension(oid, val)
@staticmethod
def authority_key_identifier(v, issuer_public_key, issuer_ski, **_):
if v not in ["keyid", "issuer"]:
raise ValueError(
"Only the 'keyid' or 'issuer' values are accepted for authorityKeyIdentifier"
)
if v == "issuer":
return x509.AuthorityKeyIdentifier.from_issuer_public_key(issuer_public_key)
else:
return x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(issuer_ski)
@staticmethod
def mongo_cluster_membership(v, **_):
"""Encode a symbolic name to a mongodbClusterMembership extension."""
oid = ObjectIdentifier("1.3.6.1.4.1.34601.2.1.2")
val = to_der_utf8_string(v)
return UnrecognizedExtension(oid, val)
@staticmethod
def authority_information_access(v, **_):
if not isinstance(v, list):
v = [v]
assert all(entry["method"] == "OCSP" for entry in v)
return x509.AuthorityInformationAccess(
[
x509.AccessDescription(
x509.oid.AuthorityInformationAccessOID.OCSP,
x509.UniformResourceIdentifier(entry["location"]),
)
for entry in v
]
)
@staticmethod
def must_staple(v, **_):
assert v, "If set, mustStaple must be true"
oid = ObjectIdentifier("1.3.6.1.5.5.7.1.24")
val = b"\x30\x03\x02\x01\x05"
return UnrecognizedExtension(oid, val)
@staticmethod
def ns_comment(v, **_):
oid = ObjectIdentifier("2.16.840.1.113730.1.13")
val = b"\x16\x1d" + bytes(v, "ascii")
return UnrecognizedExtension(oid, val)
parsers = {
"basicConstraints": basic_constraints,
"keyUsage": key_usage,
"extendedKeyUsage": extended_key_usage,
"subjectAltName": subject_alt_name,
"subjectKeyIdentifier": subject_key_identifier,
"mongoRoles": mongo_roles,
"authorityKeyIdentifier": authority_key_identifier,
"mongoClusterMembership": mongo_cluster_membership,
"authorityInfoAccess": authority_information_access,
"mustStaple": must_staple,
"nsComment": ns_comment,
}
def set_extensions(builder, cert, **kwargs):
"""Add all the X.509 extensions specified on the certificate definition to the certificate builder."""
extensions = cert.get("extensions", {})
for key, val in extensions.items():
handler = ExtensionParser.parsers.get(key)
if handler is None:
raise ValueError(f'Extension "{key}" is not handled yet')
ext = handler(val, **kwargs)
if isinstance(val, list):
critical = "critical" in val
elif isinstance(val, dict):
critical = val.get("critical", False)
elif isinstance(val, str) or isinstance(val, bool):
critical = False
else:
raise ValueError(f"Could not parse extension: {key} -> {val}")
builder = builder.add_extension(ext, critical=critical)
return builder
def get_issuer_cert_and_key(cert, key):
"""Get the issuer certificate object (or 'self') and key for the given certificate definition."""
issuer = cert.get("Issuer")
if issuer == "self":
return "self", key
# Signed by a CA, find the key...
return get_cert_and_key(issuer)
class SignedCertificateSequence(asn1.Sequence):
"""Python representation of the ASN1 structure of a signed certificate."""
_fields = [
("cert_content", asn1.Sequence),
("algo_type", asn1.Sequence),
("signature", asn1.BitString),
]
def to_bits(bytestr):
"""Convert byte array to bit array."""
ret = []
for b in bytestr:
ret.extend((b >> (7 - i)) % 2 for i in range(8))
return tuple(ret)
def sign_ecdsa_deterministic(key, cert):
"""Re-sign a signed certificate with the given ECDSA key in a deterministic fashion. Return the newly signed certificate object."""
ecdsa_pkey = SigningKey.from_pem(
key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)
)
# Get bytes of our signed certificate as DER and load them.
all_bytes = cert.public_bytes(encoding=serialization.Encoding.DER)
seq = SignedCertificateSequence.load(all_bytes)
# Get just the certificate content and sign it.
cert_bytes = seq["cert_content"].dump()
sig = ecdsa_pkey.sign_deterministic(cert_bytes, hashfunc=hashlib.sha256)
# Encode the signature -- Split it in half and make a sequence with the two halves.
assert len(sig) == 64
r = sig[:32]
s = sig[32:]
ber_sig = b"\x30\x44\x02\x20" + r + b"\x02\x20" + s
# Set this as the signature, then dump the new certificate.
seq["signature"] = to_bits(ber_sig)
signed_bytes = seq.dump()
# Load the new certificate.
return x509.load_der_x509_certificate(signed_bytes)
def write_cert_as_pkcs12(cert, key, cert_obj, issuer_obj):
"""Makes a new copy of the cert/key pair using PKCS#12 encoding."""
pkcs12_opts = cert.get("pkcs12")
if not pkcs12_opts.get("passphrase"):
raise ValueError("PKCS#12 requires a passphrase")
fname = pkcs12_opts.get("name", cert["name"])
serialized = pkcs12.serialize_key_and_certificates(
fname.encode("ascii"),
key,
cert_obj,
cas=[issuer_obj],
encryption_algorithm=serialization.BestAvailableEncryption(
pkcs12_opts["passphrase"].encode("ascii")
),
)
with open(OUTPUT_PATH / fname, "wb") as f:
f.write(serialized)
def process_normal_cert(cert):
"""Given a certificate definition which has a subject, deterministically generate its corresponding certificate file and store it in the output path."""
key = get_key(cert)
issuer_cert, issuer_key = get_issuer_cert_and_key(cert, key)
# Get SKI of issuer if it exists; we need it for the AuthorityKeyIdentifier extension
if issuer_cert == "self":
my_ski = cert.get("extensions", {}).get("subjectKeyIdentifier")
if my_ski is None:
issuer_ski = None
else:
issuer_ski = ExtensionParser.subject_key_identifier(my_ski, key.public_key())
else:
try:
issuer_ski = issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
except:
issuer_ski = None
# Set all fields of the certificate.
builder = x509.CertificateBuilder()
builder = builder.public_key(key.public_key())
serial = cert.get("serial")
if serial is None:
serial = get_next_serial()
else:
serial = int(serial)
builder = builder.serial_number(serial)
builder = set_subject(builder, cert, set_issuer=issuer_cert == "self")
if issuer_cert != "self":
builder = builder.issuer_name(issuer_cert.subject)
builder = set_validity(builder, cert)
builder = set_extensions(
builder,
cert,
public_key=key.public_key(),
issuer_public_key=issuer_key.public_key(),
issuer_ski=issuer_ski,
)
if isinstance(key, ec.EllipticCurvePrivateKey):
# For EC, we need to compute a deterministic signature ourselves. While newer versions of OpenSSL support deterministic signing with ECDSA, some of the platforms we run tests on use old versions, so we unfortunately cannot use this feature.
bad_sig_obj = builder.sign(key, hashes.SHA256())
cert_obj = sign_ecdsa_deterministic(key, bad_sig_obj)
else:
cert_obj = builder.sign(key, hashes.SHA256())
header = get_header_comment(cert)
cert_path = make_filename(cert)
# Write header + certificate PEM + key PEM to the output file.
with open(cert_path, "wt") as f:
f.write(header + cert_obj.public_bytes(serialization.Encoding.PEM).decode("ascii"))
with open(str(STATIC_PATH / idx(cert, "keyfile")), "r") as keyf:
f.write(keyf.read())
LOADED_CERT_AND_KEYS[cert["name"]] = (cert_obj, key)
if cert.get("split_cert_and_key", False):
# Write just the certificate to <path>.crt, and just the key to <path>.key
assert cert_path.endswith(".pem")
crt_path = cert_path[: -len(".pem")] + ".crt"
key_path = cert_path[: -len(".pem")] + ".key"
with open(crt_path, "wt") as f:
f.write(header + cert_obj.public_bytes(serialization.Encoding.PEM).decode("ascii"))
with open(key_path, "wt") as f:
with open(str(STATIC_PATH / idx(cert, "keyfile")), "r") as keyf:
f.write(header + keyf.read())
if cert.get("pkcs12", None) is not None:
write_cert_as_pkcs12(cert, key, cert_obj, issuer_cert)
def process_cert(cert):
"""Given a certificate definition, produce all expected output files and write them to the output directory."""
print("Processing certificate: " + cert["name"] + ", writing to: " + make_filename(cert))
append_certs = cert.get("append_cert", [])
if isinstance(append_certs, str):
append_certs = [append_certs]
subject = cert.get("Subject")
explicit_empty_subject = cert.get("explicit_subject", False) and not subject
if subject or explicit_empty_subject:
process_normal_cert(cert)
elif append_certs:
# Pure composing certificate. Start with a basic preamble.
with open(make_filename(cert), "wt") as f:
f.write(get_header_comment(cert) + "\n")
else:
raise ValueError(
"Certificate definitions must have at least one of 'Subject' and/or 'append_cert'"
)
for cert_name in append_certs:
append_cert = get_cert_and_key(cert_name)[0]
header = (
"# Certificate from " + cert_name + "\n" if cert.get("include_header", True) else ""
)
with open(make_filename(cert), "at") as f:
f.write(header + append_cert.public_bytes(serialization.Encoding.PEM).decode("ascii"))
DIGEST_NAME_TO_HASH = {"sha256": hashes.SHA256(), "sha1": hashes.SHA1()}
def write_digest(filename, item_type, digest_type):
"""Calculate the given digest of the certificate/CRL passed in and write it out to <filename>.digest.<digest_type>"""
assert item_type in {"cert", "crl"}
assert digest_type in DIGEST_NAME_TO_HASH
with open(filename, "rb") as f:
data = f.read()
if item_type == "cert":
obj = x509.load_pem_x509_certificate(data)
else:
obj = x509.load_pem_x509_crl(data)
rawdigest = obj.fingerprint(DIGEST_NAME_TO_HASH[digest_type])
towrite = rawdigest.hex().upper()
with open(str(filename) + ".digest." + digest_type, "w") as f:
f.write(towrite)
def generate_crl(issuer_cert, issuer_key, dest, cert_to_revoke=None):
"""Generate a CRL.
:param issuer_cert: x509.Certificate object which issues this CRL.
:param issuer_key: Private key object to sign the CRL with.
:param dest: Path to output CRL to.
:param cert_to_revoke: x509.Certificate object which this CRL should revoke. Empty for no revocation.
"""
print(f"Writing CRL: {dest}")
builder = (
x509.CertificateRevocationListBuilder()
.issuer_name(issuer_cert.subject)
.last_update(DEFAULT_START_TIME)
.next_update(DEFAULT_START_TIME + datetime.timedelta(days=MAX_VALIDITY_PERIOD_DAYS))
)
if cert_to_revoke is not None:
revoked_builder = (
x509.RevokedCertificateBuilder()
.serial_number(cert_to_revoke.serial_number)
.revocation_date(DEFAULT_START_TIME)
)
builder = builder.add_revoked_certificate(revoked_builder.build())
crl = builder.sign(issuer_key, hashes.SHA256())
with open(dest, "wb") as f:
f.write(crl.public_bytes(serialization.Encoding.PEM))
write_digest(dest, "crl", "sha256")
write_digest(dest, "crl", "sha1")
def generate_all_crls():
"""Generate all required CRLs. Hardcoded with the expectation that we won't need to add new ones frequently."""
try:
ca, ca_key = get_cert_and_key("ca.pem")
trusted_ca, trusted_ca_key = get_cert_and_key("trusted-ca.pem")
client_revoked, _ = get_cert_and_key("client_revoked.pem")
intermediate_ca, intermediate_ca_key = get_cert_and_key("ca.pem")
except FileNotFoundError as e:
raise ValueError(
"ca.pem, trusted-ca.pem, client_revoked.pem, and intermediate-ca-B.pem are required in order to generate CRLs"
) from e
generate_crl(ca, ca_key, OUTPUT_PATH / "crl.pem")
generate_crl(ca, ca_key, OUTPUT_PATH / "crl_client_revoked.pem", client_revoked)
generate_crl(ca, ca_key, OUTPUT_PATH / "crl_intermediate_ca_B_revoked.pem", intermediate_ca)
generate_crl(trusted_ca, trusted_ca_key, OUTPUT_PATH / "crl_from_trusted_ca.pem")
generate_crl(
intermediate_ca, intermediate_ca_key, OUTPUT_PATH / "crl_from_intermediate_ca_B.pem"
)
def parse_command_line():
"""Parse and return the command line arguments."""
parser = argparse.ArgumentParser(description="X509 Test Certificate Generator")
parser.add_argument(
"--config",
help="Certificate definition file",
type=str,
default=str(PurePath("x509/certs.yml")),
)
parser.add_argument(
"--mkcrl",
action=argparse.BooleanOptionalAction,
help="Set to generate the default list of CRLs as well",
default=False,
)
parser.add_argument("-o", "--output", help="Output path", type=str, default=str(PurePath(".")))
parser.add_argument(
"--static-dir",
help="Path to directory containing signing keys for certs",
type=str,
default=str(PurePath("x509/static")),
)
parser.add_argument("cert", nargs="*", help="Certificate to generate (blank for all)")
args = parser.parse_args()
return args
def validate_config():
"""Perform basic start up time validation of config file."""
if not CONFIG.get("certs"):
raise ValueError("No certificates defined")
permissible = [
"name",
"description",
"Subject",
"Issuer",
"append_cert",
"extensions",
"passphrase",
"include_header",
"keyfile",
"split_cert_and_key",
"explicit_subject",
"serial",
"not_before",
"not_after",
"pkcs12",
]
for cert in CONFIG.get("certs", []):
keys = cert.keys()
if "name" not in keys:
raise ValueError("Name field required for all certificate definitions")
if "description" not in keys:
raise ValueError("description field required for all certificate definitions")
for key in keys:
if key not in permissible:
raise ValueError("Unknown element '" + key + "' in certificate: " + cert["name"])
def select_items(names):
"""Select all certificates requested and their ancestor nodes."""
if not names:
return CONFIG["certs"]
# Temporarily treat like dictionary for easy de-duping.
ret = {}
# Start with the cert(s) explicitly asked for.
for name in names:
cert = find_certificate_definition(name)
if not cert:
raise ValueError("Unknown certificate: " + name)
ret[name] = cert
last_count = -1
while last_count != len(ret):
last_count = len(ret)
issuers = {cert.get("Issuer") for _, cert in ret.items()}
appends = {name for name in cert.get("append_cert", []) for _, cert in ret.items()}
req_names = issuers | appends
ret.update({cert["name"]: cert for cert in CONFIG["certs"] if cert["name"] in req_names})
return ret.values()
def sort_items(items):
"""Ensure that leaves are produced after roots (as much as possible within one file)."""
all_names = [cert["name"] for cert in items]
all_names.sort()
processed_names = set()
ret = []
while len(ret) != len(items):
for cert in items:
if cert["name"] in processed_names:
continue
# only concern ourselves with prependents in this config file.
unmet_prependents = [
name
for name in cert.get("append_cert", [])
if (name in all_names) and (name not in processed_names)
]
# Self-signed, signed by someone in ret already, or signed externally
issuer = cert.get("Issuer")
has_issuer = (
(issuer == "self") or (issuer in processed_names) or (issuer not in all_names)
)
if has_issuer and not unmet_prependents:
ret.append(cert)
processed_names.add(cert["name"])
return ret
def setup_global_state(parsed_args):
"""Set up various global state based on the commandline arguments."""
global CONFIG, CONFIGFILE, OUTPUT_PATH, STATIC_PATH
CONFIGFILE = parsed_args.config
OUTPUT_PATH = PurePath(parsed_args.output)
STATIC_PATH = PurePath(parsed_args.static_dir)
with open(CONFIGFILE, "r") as f:
CONFIG = yaml.load(f, Loader=yaml.FullLoader)
validate_config()
def main():
"""Go go go."""
args = parse_command_line()
setup_global_state(args)
items_to_process = args.cert or []
items = select_items(items_to_process)
items = sort_items(items)
for item in items:
process_cert(item)
filename = make_filename(item)
write_digest(filename, "cert", "sha256")
write_digest(filename, "cert", "sha1")
if args.mkcrl:
generate_all_crls()
if __name__ == "__main__":
main()

1
x509/static/README.md Normal file
View File

@ -0,0 +1 @@
CAs, certificates, digests, keys, etc. which are not generated by mkcert.py are stored here. Contains all of the keys needed by mkcert.py during certificate generation with certs.yml and apple-certs.yml.

30
x509/static/ca_key.pem Normal file
View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/ca_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHstBFbi4KpKUY
T2y0dK4BY+97UVzDE4ETCZt4p3GQZDIRC057agnex2XzLks0u5qVigm09mgoVDAS
Vrpk0GlXzCPXq5U5I27K/Z979gKL4nbDjRfo/vDdv3TPIapTtdFbWdMRHMX6wNr9
8ogUejvhtdAKtOaQS0UisfUWHAtrSTRTXcLHqMoLqLP1KEqzMRAxU214f6RQOX+k
nPhNATPgTHxXK7/NwB0N6HioCSkg3+tJUQoUCZUK2Pzd9uRdtGveVKqDXv31grVu
hClQTt3etG5E3JhrUjhJeh2QqWXEK1J4/UXMK+G1j+xplVphZjEx7XoHXI/p1kUm
h8skfnSZAgMBAAECggEAHUFb85/1jMecDBiuoy0oxLlgPx+nSEjWMvTIWv+kynNz
Rj3yzG+3bHSnwd15VQta1Sd4zpL+pVHYDQe5nMVPeXZFlfXkEY/YTlKjh6R9sQKH
RZSo+RBINyQyN5oF+ud6+TgKjMo7UsXoDyX1u5JArYtWJAtmb6MnSLLrZcbMAXZg
qx4hg0V8c8TZjeITzkbArTlWLrHGUIILbCAftkMtYZeaAsxdFvXawokKV2MRxKuf
6KIp78xMzcBCpUUegHXtiC5O5zDxOWy9hc2GIxyp+GTVSTsPf4D3rg1lNTPzVjBo
QX4I46s7pSZOKrX/rQpVzd34PWxc8iBEzYCgyt1CNQKBgQDs4W9J7Rq3mXnPRbML
osv6y8sqqDdLWlXJnJ3WtHnf6WVTy6ocCo48olDyd4gPG6a9wSW+Zg1kQZh118/4
XDe8e3tDzVMRxV68+x2Ekr7mD2Sxnrho4KNqJNyT/FSj8kk9xI+Rw7vfJfGMhn8I
GPEcujYBcWqx28KD8+k83oZpnwKBgQDX0RmtbJfWodLQdGFxgLAybyhXE8v10Q6d
eCFfO4BTK7Kq8oaTVDHN2hDSTbC4Hhcc1VvxKCBHBcAu/g1v8y8KQPaz3PQMHyFA
j+dFj2LFQOemTY3+yPviuh4oNq7rhLmDY6fmfSs1c8GW0HHZJd+9WfBsGLcQTaox
uba7ZvNmxwKBgQCnFeCdAYzt4mjkRiKj24IL9kHpZdwS37ZRTpKbBpRM12FsuOTV
gLCRnmCAlsW2+mcjw6Cu62cYx5gVz1NXuRxra6In0iV9DH3lyS8p+ySCPGtnSjCD
cahyz2tzSvIc7mKxGfu28pyLK0V1PM1P1eAExmgfnnOG3x8WWi6zi7a9uwKBgH/T
kNLgS/rLdFMVa5XPtAzbO9h/mEGrpm1sds+yLWqVqkiIR19B8hHMBESb0XzsDaJ9
WOy4aI3IgTEUNp9FOWpoWfbkewQm+AoGceQIbmcI72vX6a+sGU0MEcqdwPMsdLi2
sP7aylnpixMpuRT10tSTTcyowtz8Mz8qkWnkK2yHAoGBAIXs40vL2OsuQa8hxBy+
tz5LrpmViy26oqIVnmKJCPZA9evRqyRemUuAcW0OnGahCvh9cqqlsUZwEvhyuPvH
5yqtcrdFLXuwlhqq9F4B1zfRVtUiFbsC1A4e9T41xx+vVt23L4W0ixVL3GgpeHiD
8Lc+eUPFccYbmN5BFV+pN3px
-----END PRIVATE KEY-----

10
x509/static/ec_ca_key.pem Normal file
View File

@ -0,0 +1,10 @@
# Generated with: openssl ecparam -name prime256v1 -genkey -out x509/static/ec_ca_key.pem
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIE1gr9+f6u8qyoOWOAeHBUbNWTKLsQKwUrQbEng0BcpRoAoGCCqGSM49
AwEHoUQDQgAEw+5/jP9WUKZohTVniQpjYDwSDUCfydLLICGjkR0CjH0w9u3mDm2r
C34yn09Otvp2DhnQKdi0IuUUjAtHx8g/NA==
-----END EC PRIVATE KEY-----

10
x509/static/ec_key.pem Normal file
View File

@ -0,0 +1,10 @@
# Generated with: openssl ecparam -name prime256v1 -genkey -out x509/static/ec_key.pem
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIEcZqWTi/bTuPSkdEg/nSXCYRiXkaE5li0wrJpWxAxk/oAoGCCqGSM49
AwEHoUQDQgAEEN8umTG74sf9cUEp+MqpNOpLW/vyvIEQNfKxngeX+DbBhOO1TSq1
41mW3Cf9kBC1opeLdw9IyZ3zDmuInIBwBQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,10 @@
# Generated with: openssl ecparam -name prime256v1 -genkey -out x509/static/ec_ocsp_ca_key.pem
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIKZRpSNWP9hPm5AA9LvzBq5k+34lOYPykKCbMJ7YFMmmoAoGCCqGSM49
AwEHoUQDQgAEa5n3PsXSokSd8D5lr0k2AUx/96gxCT+tamroMapH/sbjGtDmCHRj
TNU9lGqwWUDwT9YcqWo6v3Sn41B4qiS2CQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,10 @@
# Generated with: openssl ecparam -name prime256v1 -genkey -out x509/static/ec_ocsp_key.pem
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIGOugAzyy7Xmb2QrMm5GXxKnPmy46D7bEtD7ApFx3dMBoAoGCCqGSM49
AwEHoUQDQgAEZARD/HCqt2zxJGb+jtHGEMmLrfyzvL09j3iwcxz9FmSdqhgJ4rze
LyFidY+5BWVIL4ULV3J8ZdPKlvirbJ7NDA==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/intermediate_b_ca_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMjtMFYF9r18yA
anNI4pY712brkcklesA0TSD4PpAn/n2VQM3gci6iwTPybpfQp2BGnTirnc+V0O0e
xF2twRPTe34wQMP4gc5MQMyjoxCCcfG1qq552y2t9NYB3UhtIhX4yx5C3imbrHMj
0eysN6PpeLiKOVkwO7sHQ+hd/K0lwQ10U4e0F+7jMrIKLS+xvk4OFMYvZSo7vCCj
qyny77Uqs//C2LgYeaJrLIrDc0UJlmhYlN9jiSLkfGQZ5QAbh/xvFmzDSgOKEcgZ
3uBYsQEXI3j3chJ25vTM013bFemK6EaZTA9p/+mlshjZYxB/aVrU4nMU47nowqUW
1gVBo4rfAgMBAAECggEABc3zt6OsHCpLzO+4Wmlw6+fJLYa913Nr6tAEJHyEqK3f
BbzeBVrCxK7eI333OYjWVt/1O2FyAi/4hTal6zKfC7w7BhwrCMKI278RpNRmuTI0
h/wnkUuijdzJtH8r+UojUiOpYH+0seHV2T6xYZL+nWG7PX4ycAecigXnnRXOGqka
Y4Q+Cqw2HFMhc3fCida+VjcnL1/UbeCOGKkAxGb002O4iYLgEmz8KOjyIBthjEw+
E7E2pHEvyeSGqgSaDkAerRkMDtSxNvQMhjAS9Mxp6KbwlM6UlmmTrz5kyvqvzpzs
EKLL8gOFdUc0O/q1i1GXw4J+jmmruWr6ggKaJgvT4QKBgQDWt+9gUMWqno5LV7PP
IEyKBQ14KvMXwUwxo6BIAfcrduvqQxIR+lCE282kn6doKvhMgIq5n7nG3i75ekLq
CDEhthf2FFdUuXU+jluB4jJiqkyFGNR3+Pnl7RKXOa/OXS9r11RpnLyrbISvfSr5
oxXOeaMUlNZI9nOlbsQ2686r7wKBgQDz4s2R2yRFwSUBb3N0/zYuXA+xVamTadQb
bzYj9j1thrzaFxkp/+nlLh96qq2r0L4teScORcig194z/WNlNDcz8Q8w0LV21iCf
0Csn1Gs/zGVaDCiVuIAQjPaYdpzVBeJVkIVbQzfYG6CPyap1MvygzsD9MCISOZCs
GVkLsBfgEQKBgQC97GqXRjrhpWf16riIgGhTOQ7l+Q+XNopf6fzPVLW9w23/g54L
Ot9X9VibwgCA2mlQue57LHZWGpdwYp2nhuF2kSv2pZ1turGjSKZWZ67rqPkQTZs6
F4drwlxMWWFRZwmYGRp4ZIRaGR3wYAXQVFnojZ0bil9UoHJApY53ifMADwKBgGzZ
cyqABiZj1+JWHc/AACycxhw9wVubxiEgd6eBRVVW537nBEIsh/XTqhUTjEO8/MRK
6FWEa9Dtx6yokO4gaery0fbVj8gkNZdeT4SNV/i3fxy7hHmeSPoaEA1oEwM4hxXt
VLewvoHjgrvqI/v+76XN4XCfRPWhX6KQBaAjzeQhAoGAAtk/dq8ojhStGr0MESsW
isMCJnnCskmrJNgGkBL9+kOGk+BUCHUMAF9omjdAS4b9ZCRYJtiApiP1SboqQxvk
/VgV1Ugyoo7IfOQcf7j2wJf9qkiVVVWtATvsmQ+Biyp1MGeR7ZsT7GAqVXgBnwaz
4znhiqGftOkyYEySPUe2tDA=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/intermediate_b_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDaGeC9rIXyghgp
JOxaNKpNElTCb4tYrX6r5YP656YLupa2M2bBSR/OXMh2Je2UjtW2l1CG/dPefSVw
Zvbrd0cC1TGMraBU9ZSOHj1HmLG0g8Zt8qDYvIyPgBLJgSGKwtzrliKUF2/1Brg5
/qMpL+rBbV5DccYUH2dW2DzCRNQJIZxNOJOB4CmJS1TDIjOcMtc+SQfiBf19Zweg
AjQv9i/dyJtgSlF4famPYUtzkXJL7Q+cUteMkjpJWTueOr+ozhdnPGDMoLPXSCnd
pc3J4wiCmknt53fW3zV+oEG8OkkqDvVZEDBqMGHPPVEUr2FC5Z+H2LKWrkRxf1EZ
z1b1cPjrAgMBAAECggEAH1ZViNtHmbsgjpTcEu/7Qjyuigtt6a1wBHHjX0M2g/vo
2MAU9RO1KrkBIpy7gLtvMJ+YNfU1ooO3w+k/dEC8pscMKgrufRaWJD9rDaT+b5H5
imWwv8ODrMC5slNIBwCNrpnxWPbvIrU29jpEpk/Yurcksqsfy1dhyUQjosQx9Sen
lZ5dMfh1fH4Ir5NUv6Epf7IzmT4mn5zj3MdqNIAp1KXgl+JvvGpYUmsgOzaUdrHj
UzMEj1gCxmIIQLczd5nyeg7dZimRZM80SGBloZXnTW/vzpRcFmHl+OiImp2XNwwM
kI5umheje+8A0664BR1IlDIJdRrk/LTY3qVD1RKSAQKBgQDci6miBM1xOjNB1EgB
o4y6GR43+Cf498NOr7dvTa3nRmwT4FY2oCC0EbDx02MgvSeDeRqZXd4K57WqFguU
FPkvuN16L15UoBSWbaRdbqlYmCm47HcjUbCmVmbSeegrvXsPm8jeNUubOvDMaxLU
ZE59h1qG073Q9zpx2KgZZOqq6wKBgQD9KZ2MJHf9fGLKbJMz8YBVwD8EZfPTIYMP
CHr4ikwikA5nIJw8Qt0Df5RpfkjjbpnG4oVBNDGNNEwiMn6Fqirkqc7GEk+VPPnU
ZaSLA1S9mEaxXtixo/GOmuVmvuWUAdLNtCvYVGVkYV2cf/l0OsjWdx4CPn3Uv14Z
Ux6p7wNqAQKBgQDKqoz3lfI0Woc/txN0bhaj7PEX/bK91vBjHpYyce+c19n5ae3P
xNZIovk3QEmXjDsDVgZbaSbiXotSAXAiZCOY9wiPf3fvzCsfESI5ubdk8m9kv+e7
TRZHxJ44TE5N45FyhnXPvKn9u+wL7VkgVAzMzdUikPGdVZMfizjuHQ6IgQKBgAn9
TGQtRDbSY6uNITnZe7DmhxYLV9Wq6tr7AK8x9dMfUBItrTyLfuEWdaq7+vBOeu7o
HU33W0UxHRf0Wh24Gz0uniQesNk4sLr6z8VUelGI4rE5Bt/rkiqIXijxu2ldsQ3A
4EIHAoE1flYgjp1RfH9J7/sysBBnBLWHHByke8QBAoGBAJM0fNzdJbEW/L42kfQR
b4zqo+t7hgKwfgbdvZ+fxz0puItjQCmXKTfibxmR0r/DHmiY6+bFqzLPm9tbG3bQ
ETSZetRt+LqKRapnTxHdDetg5yFIXSHRGEwRikqe8KN2zLz3g8Pdx4+kfzqHARDD
IgnQD8c62X9AoRNOyq6bzKmc
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/intermediate_ca_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCvzAYkXUq+vGPL
4X4hrkuD+YgSuVbISE3puYrBvR+N4cjJXX6PcbGqNVVsFY3LGczEyfDjGDPnLy6A
wCGi/B2tQSVcq4vLMH3YZRkT0rbpJHGlDN7EM82OYUJRUeNvZxIeLuDyicktuqYs
DrVPOGRWYzuE8TKbcAsu0QJyXzteQtuN8nR5l8Zc8f+lj1nMMni5hXNAoOIoWvuy
kd1pqIwTno4KCJpv7mo39z/2C86n5QwzzphqJ5as9xOtFkpv6IUwCPbYoV42pdCP
2l8kCjpQIQs33TZKsukdeOh5iNx42NRLtY2M9eYmomlJln6wwRkYpW/dsdSUgL99
72iM2/JfAgMBAAECggEAAJ5yxgwz4Qb05NUrbiLjJARaEqJ70QkkxjOWpxjPOaa3
jfUkQGQJ56K6jjRnYeYEnZsTXorq2hqzcR0La4NXxCAsSs1p+hYGADRXjtdKBZ0J
LKzj0yz6UNX0i+sweDlw0PMRlWcaWPcMpaVsVK0Xu0Om79B3vnIoCs2TJKaLJQbU
a3daXDMXHMWPI0au4p6d9owY10ZFmTXokXHg0aUPh+gp5ZIABqOnMHn17G1K0HqL
RSuDxR2qGr+xyU9azWBooV729jvb22DHb4AaXPZIOKDZWgE73+LwxHM4RIBMQ6G7
NCWBg+ECMfh4vC4e7W3php61Y4h535SL7t6kax2UuQKBgQDPbmRFYW8nj1KtXgvB
uy38oa1WJWgVB4RFOnqkkQXriGTQLwGwryVrINTcOfXJd2raKmnnHb6qFwL57eaZ
oAFl138QWtvvZyvv+KMaFJ6ow+wFEE0gTFWPsjKGnmhRnKQTmrbr3KyMrQQQ0rYM
9YiVT8xMdEfPeFc6U93XOTjSRwKBgQDY9XKjxmD9kn8uNF0MpZ4wM0reXSeiaSsw
hMarilQ8jLfif0E7MGvm6l336FvTsdgAsaaSu1dZhXfHPcxbZG1REqW2NWkc2JQG
DBE7qyPe6StwNHLoThjQE55YDBIuDZUrx8AZjQBJO7l6HNvMV4YYMkx94F3UrKj7
4dMpcCETKQKBgDLOYxjrSIJ0BFgaVN7areTW5NHYz6l28drS+/8a1kxeV/L10IAq
JgwbOofGWoFCEpXlFZNaIb0fbccxke3G1xDOu3ySBJSavJRGXgyhSEsl0cVbvMhQ
ahSMHPwECKEUsMtsdalHn6vFJN3J/nUmHpITvYJsaLpUS2kp6Ygxp805AoGAdoIr
6pWz6Q6adcyYfw4ASGfcH3ZW7fnwY4JDWvQmaySaVRgZs5ERf4LJbV74ubvNNyPS
zxeR8Q5cjPKOq+VBaSV8avjlv6H1yQ/SYftrjpli5tlfYtE18IKm3YVKcOlucAme
PtasL1R2TeNxlD7CunjPG3rxBfiCHYQO6fWbu3ECgYBXdv5F/dy8QKOAl9K/GNUn
359bblP2tUJvHUW4jM4CIiFBKdXMpJ+3HPqqLIUpaJW7LAweols8PWJ6IJpLhlHY
A+NTR+6nlmwgmc/AaTF3hm7/N84nfC8qMsLRxcer9DzEHCmfMj80Vb62Hg2HZ8f+
72vuEq4lnFlOxXs4/dHYsA==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/intermediate_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtsXu8eWYdy+l5
l4Muc9w6X/g4SbzVLFL2evkmTXARr0HzqNKSRHdVLygL1ns1Vf09k8gPYgXkt7oW
26NuYSBLBrzLLEct+XZ1rr08MHls250hxY4F7nqI9NbgfOzZEu2jyvZm3Wak9/NS
dvJX6gATELoz5TjHHaiCMsTsIQU9SLtdTrc7gQ+nt/5OWdyoq+oE8zmOa1LqT5rH
Z3XUnwh7GlVXj0U00ep53KuhAOdbYGpGcoVcY1eOrHp3ORsw1NTUP4VqFVN9Fjzz
xHr0QTvmNt7B8MmI/rGRsUlE5dPgUtf9xD3D6dLOjPeL3tAwClYg+r77c3gispW3
9cWzZCO1AgMBAAECggEAJlnuds6dUA3yptDf+7VEVrVTAuaxJaaMSPUdJyppCNaY
KttHZ1lruejYIEkC2mN6r4p+XXsozvgMRDjJ7LjQXxCFRh0oOEwBLnnfObeAUBtr
pgXPVprx/mSFP3sF9uY5h3Vsk4jmPZ2r4bT2zJeT3aHPY18E+t4fE2RvW63s0Ltt
yjKdGMbXeUHvyJkYtUc/jXiGUqPTHQM09hQ/vDcRTs5Lalf5hO/ki4qs3VgjKPET
CqgUg2WsImw1tpF/+gWnP7n3kDoi2AIhjJP4WB+pA656LXnTd1UD9mCOBAu9zHgn
QNsHH2SVehzuIdE/w96hk7N+8YFWZXJYBMyzYlQrnwKBgQDLqy+95wNPAnRFSuyx
ZtTxKiTA/89vfTq3vjE/k0T4K99zyT0KKlkf/j3KItkSqpntZfbUZqBuASmZx8t8
7I2673jpm7aTrT9dmKmRouJgXB+w48UDR0HYPuqCuHmL6HIWFT/BgA7b1e6qpn5s
sPdEQeJdPciN2FNt2Ejwi6GLmwKBgQDaUpclEsmOAv5xgU0bb0V7of1vjuXyrcN/
xk8UhNRTsodY46XMGeZsZMJ+q2scOS3N84+ZgsG1cRfX/nWvQjkn3OrILBFd6k5H
Kfey0Y1CUaxu5H7aab8gOPuBiJRWMDCVu7fwx80dZthFHclyOOC2fZ/d9ZolTZ9k
mt7MTyhK7wKBgF/UKB5+N7xRN0vzOPMvoznlzm1Q79VRYvNZdeqn7GeonPbp1OKX
kl/PTFtzkheKVeqxczX1I78epOhKbaBV3Un7qzSfo4RQm+P6FK8FqOYV8oNUaDpm
qMCKueTPz8DYmfVyAhGVo2gkfKumsw2JJo7jQRMGIvs6seaZQZiM2nHJAoGBAKmZ
ZT7wlFDUtJK6TosUapa7ZWSnTqyyHeABzubytPr8AjakSeT+7cigkZLTWVbIeHO4
VIJ9WDu6SjqJuyRVvo7gCCdOTIN3hC22RWzNav3s8pYGvSCw6z995KtgzVMTBnsb
I65RmF7RyQoQNLCdzLsXZfyIUaHO5hbCVHfEullTAoGBAJzknKJSSbHde7+zxkbJ
hvMKPMN4ua47KhinCgNzeheP4+u1a6PwaQ6dstt//20ae4B67ml+WgYvzn4m28iK
ndj0y/4fP+MO3prrvijjb6fCGBlanLBhNazffYofC5jDMKaLUn5CG/A6ggfeAcDp
5IriqK4zJHIfb3uw/E3+nLaR
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/intermediate_ocsp_ca_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDKOys4mHEEVLaB
KQOqwqYOXVR20sd52yByciXJwpOcXAXnPQJJHGBkre2SX9cJjyz8YfTRhBoay+JI
Fk1CoERA5yP2VL/ryLhg3kW8hbR8bhfMiUUZjy2iS2vDMq+4mVtw4udsaA4nQo4B
VBXiK1+W8XH8YgdhXk1nKugg3FKrmbA+TXYcuGPgHKsvWSNBCRXquZzKELfdFJGH
Jr9JcDC1EI0a10pWvsVV3aOJ+omkEaZpFZlyUVnkdBXjhU6GXo9NXg68kz0dnwLw
8WTlazmlO+cOrWC09FTM2txk4ifJZEC4JApvikCwNtJc/DkORE1M79KqWqm+VyzX
BEn+/exdAgMBAAECggEACiEicHBYk7UHaJ+BFQR57YvWfijfVtSONSZ0Zs9f/0Tm
ufAwAufnmrNj1U7ioZJyIXiy5BCNpC6twa0IS84b+s7UfoWFx7uQ2mZqC6kg0LZx
j7n0v1A1kJcCqZhBa2ngM5WI0q6cdSkb5sxrM1UAaKfk7PDWEMz4x2kMtDSphx5a
/NQx/ilqNeUjXHW/1jguNCHoDmunGwd0I/GvPEb3yNnajCZ1WQTHgeEVC6ONSFOf
T7d3+5z5IiyG6HYsLVeIVq2cjdY11e1BxGJdxoSQtu89j0gUinjkTeQjvzKjQrKb
28ZFqDRsmpo2O1Tk34tgqW8IIKhj9vcDdm3z3IctmwKBgQDwVUc+Dnn5Xz/0mYJq
e986mmg/sGh1KkJ7rwF3EMC3jzPium6xwlSx8uobYewBeaj2yR0KG6oHXROqvz5H
Ut6Pn5o6Acxq60behLTX5GZPCnwYWw4TAsHfX7iT/YXgJ8d4UjY/3LxS9I7yjdub
fLmSSoWYercXi7kGEmWOA2IzkwKBgQDXagmreY9GbteuCzRdhJWPsAJWimXCPz8V
11W5qRjzMXzg/R2EmyIuiocale/bKzw2TtrXxRilAn+UIqZxupVJNWoNETyjigsd
tHrnofd9g2g38SRsMhUka+Ee0QYR0S7S5XhjiJZlMbw6+hI2DAbyLrfYrBND59Hf
dyoSj1U2TwKBgBtD4Xg11jqnRq8uNzBzayjP2aHYFpGsQKyddxIV8XchpOZE9kfu
XwNtJogCvO6R6cxNlqDN8KUzNwb4+UzIJv2uQqXwDEvY80pNTeLsQ3sWGmv88ITR
nEMGLf+EFIsQmD2bPhJSrX7PxePYmiByru7cy3k3+suOC2iX77ODyMFHAoGATPxq
pEv3dpaaomsCtgFyaj3fOAqSP4/W/flNe+MBNbkUBlyvtfqzhqqfilLXvB6BkG8y
KzcXjbGM4uZXUgH65IUgd7cXUuM9AcrEug/aoZLbJlMaT0i+4Ztkg1z0rF10PI8i
LYBdL6FMwk8pPwOhX+BueBNXd0dcbF7sPGHZdGUCgYAo0WOD1xYM8XsKwM+MRsw0
fzwNZ9Fp5ebyrXMLtTNRdbXvFLqeNaWR1NMWP5S9B5S/PTG8jgz+I0Ks/5WIpFik
3uIPQsB74fBBFAdBDKCdrJOCP2w683BIM6v2ORK891w3EL9TxpZSiVVr6bm7TB+N
LEBmi5V3xUXgKQS57cGxoQ==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/intermediate_ocsp_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC3UAPPT0kE8eSm
kll2YQURGadQQrcQA2JUtiWOOpVhNO78Yuf3i4whZYlrsYchSMXGPk2nCnb4QUtm
AwqWnirue2sHFJfXhhp0m9OAMFkAo2AylOZMjWGKNnHif/hlUjrvvv1Qn1cUFChz
9A7Yb05MNzukJKU1xyUkrq2X18QL3FoK39rWCqi4ncsMjeIDp1Flq1q38lcbDnq2
TUOZQdQcYd4d9wjS+ALdzzkcT1PrxOP+Mekpyjo+J9wb7Nu7Cjh3wGvBnu6CBf4z
8fF08M/lm3aw07u/0Yu8Uhr/GvFPYsoxx14s5lTGZQHgIo72fQ9qCl01oYBzFUVz
fwCOxogzAgMBAAECggEAHf4+kVX0qZV2hvadIqxfKtwarxwrXbhgB2JCJNJbDKuf
irYYJD218OTvJirG5GBG09fv1qv0qUvtrUREID7C4YBaE69/5KixfXDdmzTN6zfQ
DpakU9QyKG4eFiRAHTvmHsIOKnnXwpZFxCsjnrAfjILhBEtmqLTr0+OszZJlJldh
IboKQFcIXym1VqpvDml/XicNaYuZ2bHvqDb5Fw33hVee4pI9IefoBlLBW1gXGMm4
/5vTDJ7d2OxjmUGA8cAhaKwKLn/U/UTmfLQfMhDdgwmJXRx7ZlA0eTXfr0sxiFL3
kfRsM5giiGSSSleQ0Q4lj6a/k83BtQL1TAyelsesWQKBgQDBmYKoORN9v37eankU
cyloRVrxpNJRhQrLd6ZmBHXFu6DEB27Oj94s85jYZ7ClRUvRtzIFF3jIV0/a/dNH
/Gw3hkP0oJhfBXKlycaNaYpOvJGzLpjlR+9VcXovdD52Pn8OI9pT7QAyZksDtXID
J2yHnUzJaIwybfJQD1VO5mW7vQKBgQDyZa+D92Si+43UoYODUfoJUQ36z4mniiFZ
9qgr3Pdx+PiUV313r622WRysVfL4co0tpx7EnnXFFV5OekAzSbRw/QGvb0i0FTpf
g8WMDX/21lBZa+M1UwIEaOqRcDJuVC2ge104RzJD4bwCQFKlb0JpiE99QD42Y/Kn
fZEToHIarwKBgAvHHgbD6ialRr+bNKCE3QkF5yF6SH1DHcQBFHNyZAPShVZHqXsR
j4+mhi7sJ/f1/kXU4ksjAWsWvLny5S6k8aRzG6E/P+XP/AiP/O9Pc2WU3TxMYmrY
dHv7Ola2uLIS3UHr9nVSnsdyJ7AjEruUY2rgq/I41QagX7R1KlhxddD1AoGAFrpk
H6qVvBZ8MQDH9Qs9t5vrBKZrENOJ1waitCIu7XfbzwT5FbzaO+vVHW+draAIDszJ
vMPi5Qzg39jkpip2CdYfT1TO61vGMmiHoF8vrXRg6lGMZ1aWLNWtkN+FSwUHljGb
Bwjd9LF40Hk5hpuNDZojYeohKzZp7Tx/2uhDaq8CgYAN1+CRho52Yun9ShXcjPuC
HZOJTsoinrVZ//zSbaW+HnUCebu7PBc9ZpWpv+aGNGASddN2YMVAIrU8ihBtN9O7
f0Y3jNZDhIrl/5oSi0dAEyznCExIQI/+m3EPmVXgqAfO2TOMS8qRmI2gGmaT1lWH
4SUBvM5iFBJJavmiCtL0Hg==
-----END PRIVATE KEY-----

30
x509/static/key.pem Normal file
View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCo9fNp2LLX5iYr
JOsgG41FOv5hgEoUpCsdT+L12njtYFvepXaUpXkRkwM/THJzzDUg5eIUqfLbG+d4
FaE0Lti7H/iwhtPNxHw6vHLB3k7w622VhEazJXD7MyISI5oDliIWBVek7FECO0wc
Slav65fbN7gubKfAGwLMNdu9Hx23KxA/CzQMrBTPNjEOal4nQncbKVArAJygASHn
u8+NgSuLfWtrHMjj3TVsRI/17xvGdUkSRJwTrPLHT7JOw8j0N/fd7VBQh2CjLfBE
TJkl8+Q3EAwLYnQiCeR0WbJRuMgevm4xkEGjW6Og4mN3Po639psG46EJKU5Ud1Ja
0yBi9qbVAgMBAAECggEAEPZCBcQArk53Ufj+lsZVUBgsTfb+WOSjRGnO794LKk90
YZ1sUl9rUFGZL5tZ2Ris07zoTalDDW6XdfV77bxvOxfqVDRw4nUhgJcHEUHjXGnS
IkK5g0YUuc8oEjibP1Vs3heStSaZOldgHG31FmuZHuOQ3K5BR/aeOQiGIw4S4l6p
Av0QG5Dc27oMwemnDpZF3jG4GghXnO8v0sB/Trw0iDZ3cFk5B/wO6or2tW+qyPze
POjYN+5Sm+wvK6P3ZXjuOByF8YpSJnnZiiH9AfTedzMFfqBohi7mcXwGxO2FJ7LN
mIP5nuWsuGyGD2WPze32UfeP6GRq6WorNpaUvxBgYQKBgQC2vHbvajeUPKaO9DbT
x7oW5RYFSQwzcbEik1V6L/h/Pt/SmzhFPiFKR/uXXqZZnA7lnF0I3R0N4bNY2QeF
8OXjHhRJLyuXAdbEMW4IkYfJvPOxiXkZ+qyvM1HN73W3RlAanUNVp6VkJP+7oz0n
6JKPPwSV5zzICB2igrfvgox/9QKBgQDss5zkh/VYvBTzLtZDooN3FP0Sr75H9dUW
5uTZAk7y9qJCn5lJObJFzHCwR7yzyEMvebbuq6ulMPzkTGDUwOhaxEYrOg5lw+6D
SCpitO/CV7vtLvftisXcoXsOdRBVWRvQzyPCXTCgMQC+Vz6v5MB6K/jsdB5qRRwi
vGt9E52fYQKBgCNkSxDBnLQcLxIe4IOR+ku24NXzOOa5zVnp+TMqGVHjxovOvk5C
40W0vViq30MZw5Ta/PXbhWYL4aWCmz9o0c10JO+rsCCWHZdwD2SfcxIyg2xOOOM8
NrfUE7Lz/vOZLaiJ7uGnD5Reyhz4V77j/4a46NVzrMT9NWglMySzPy0FAoGBAL4f
BsYI7mh3qdwqoq9wuWfM0/lOb+gc7SuYCfjEgeVldK9OwjCuxyKJM3pkJI3DLTPU
77qE6TmmP3qgXqaEzB0bycCuwSG8XrfUHzdpXascDTZVo46JCKROkCjsnlHvYQg3
WOGlOIly0sYQDan6cx+uciJ6onN5T0AXV77/InwBAoGAaqFVwTXL2ldvc8pPKE+v
tkTPXp1oEz5JPTcimGpdNVVD5UAUKumY8ojNWbCq3/joVbDapi1Elx0CZGGa+SKz
+VCbxsCeSWxDZ7moT6Qrja/YGHBXGEI6UMUCTKSQeXzBe0k9DnEJNmPMMU0f3tja
pK32ytoxQzOz6iJiS1Qszbk=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/macos_ca_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcHqL2EAPXHo+b
mdqXyG5o4N+7zZRV/1KLj0Div/2bektVoWQCoI+vnQrYQj34J97EeYSanXMHsaCq
4IckOYxCcq67uYkotW9rT30wvvyhRshXbu39nyb04hKFZGpJpVBK23XqPiy0yZTl
5SvpZQ8z7iERa9B/GrJngXsRgTD43o6lQcS7r9KaIHz5Bc21jj3NRYzu+cYh8Zmt
bD6QhwnY6BpYYothHUwVymkBBqWjmy+LmIwLUwJmfyBEt3AEK1ZgXZOxbIt+xmTS
Zvx5Hpi/xGdfUeJDjhGp5j8Tvlbd9sAPhGrp1KTG3jjsEnmCmXrrCMGXvgT5fij7
GM0yiLZdAgMBAAECggEAFl5VXwggZLweO18p8MFpAGHn7JKiBEhW3WQjGdoETjiR
fq1nFPFIZRMNMLsdAedEhcYbd8PDbYDH0nPlKQ2NyR+BZahJvKlyU1/KQie7Lqhj
oBNmygX5oPCbUr12dSLYhEE5fdx2r1iKmv3g8snmCby+xC48a1m54hatOW7XQ3D2
k4m+JmKD2eX28DyyuUhUhHqPo0cMChOwDri2ZKtjGh9QF9ov+R1osgVgH8DN9PI/
RVbi/nBiEWxbbmh5hD7XFGfizELSgG5RFBmSrJqMRrgxjpHnT7bGYnO2qhhBwe/I
cnxpBoUPdS2iUbrAyM3VOV3Ne9vtWFnpRhr2627sQQKBgQDNr9CmJmDikFAO89Yj
P16ZmxI6j8QmIuEI33BhUHkuiSjEIjL+qnV69hhgnoV70fbxsiFUQSU9VsswhcNE
WNPWYjt3bu4SFneEO9xs1kVc+VsCiPO2NMEUMqAQf44leFTP5nDiSNGvgsSVhbRR
759gR4rA+ifSgTr5oTMd5r58OQKBgQDCTukV2wdykAIGlCncIq2MLrxlrbVX/cN2
SzWTthvuPtVAGMnc/rOLkGYg5AiBSRpI4AEo7CpgFZSBlRSPpoileQI7/Wt6drw3
KgQ+AXj4kHj7FyjZTDHcVcreNm7K/eHHGFA8DIjf8JdHtE+VBSNFPs8dMkugjOTB
iQBR78ETRQKBgDZsp/veudIZN2XNdULcWK6yTo96TP9+SScs4DKPtZDvr/69wdqK
xg0kIu0l5NIPi5UGejUuC6mAVsFfE3z5OAxI7805Z/sXQMaXhEq0I6RnQoKYNExp
BxHOF3ZmGfmmLmLYadQmSn1zT4r01vK7QeOa6ocHahQUJ8O3uKvXy11ZAoGBAKDe
2iVpIKJdzf+KXZnO8CZWb04zYidGhrSCkgoIRNmcFcwqeb5I9XeABr4GbXA0iNl6
9BrgZDkGxNwABHTmKM3vAMWQC5LpiOyXEcoQSApq+m7P/tbhOYq1UO9m25WeWnYO
kCcXLZ9SPr1z8EttZIUo+iqvAGQdIiuFdMlhmVWNAoGAXcfiI+j4dthEvRqXpXiE
nu3p/7QIsauiBvYpP5pGZebh/WzrxE3KJz1/fOEzrB/uZKi/WGoHJnD0vieUQiN+
9zBdyYC+zmBR9xKZs9ROA7B7BQL8iQHyiDLw0dRPEkvRtxZKxgTcJVI3hvNgDnHY
35b42UXUHv3RuS7PU0KY8S4=
-----END PRIVATE KEY-----

30
x509/static/macos_key.pem Normal file
View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/macos_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyH9cCuKea1fK0
FPTEGWpsxADfVgIv2onGgjtTM2pcjWVknJt60cPfawlYbvsaKxaUJU4JjtPK0zJ+
e6TgzmOO70a+dPTKAADV1w4X50rCropVlMKED2MU7lbCzmfiR3qTrx/2JjWzb171
5ziR6CpQTzmPD0pAeyVoCifXzRn6ZBhEld44gaqYoOiN+k1BsqHjJ3zUuU+dyf76
dBdSCD/8wb0gcCNmZB1Mvw9N7XIOs4SARP56fNAhp8TBVn1LFkOhS6QryE7yBitx
qfe4N/0YbtOkIZ5vHdX/EZ8Ywm5zIhMR7sJaveTdwdqUo2NSFzvixGd7iD1f+UDy
/as+/gjpAgMBAAECggEACSJeW4aeG6/QgiEX+y1len3joJBPzOXrTklz4tyeXfAn
TK1GQNpcbcrWoBkS2eDvR7oRAib3n+1MJ9XN2vRigRwul8o2Gly9LjoYwCuNdyXN
tL1L60tBtLtTKiq9A4rQU531qOEFPHYf28LXcQ4Di3pAlKA/Wcam4Kqyp9ud8yvU
MfSnAiQtHrHxpzX4Qp8k7sU4AR2QCPCf2UI49rpi1KbwOLE8skBJHmUgCdlvZhMg
ykEos5EEUmeqIsiIY8mZbo+FDrTLXg1BaprdgkHsX3TKMD55HMXPK0ommmyDsivp
wM5AUtIezK9N/mmYzQc0RT2R7oeUL2PcrJidOomcYQKBgQC2i3d5nu1ZtoeXcIO4
2kWf3PY1tIMJM1ZT3qUAqNKGbJsPB2poRwniltlHfTgsr96Ty73zZA9mQgtEGDae
TIwQYsWKy64alr78g47pYLyH6IkUhQ1WvD8xMvTGz4VtjymFytW0DywfzN/bAJbs
QyFBaJ4g/y3wYvD+onGxRJkVeQKBgQD5zQL5J2Z6SxSCrFYTKzLr5vzoHK8TIcBL
xHObNOKnOK72y50/m6s/7wc06qqMuaXHtrisdoXMLmnwd92RYyCzxlhFk67e2DF1
DvP9Sd8VLfsQajsolQji6MSCxpKh41WL3vMJEmLu18ho1WEsOj78q91m/DWH2pRH
sCQ91kzi8QKBgHiK3ml8rkWYyC8TyJfv4xwu4JMUUZdoxC/8DT/DO8oyu64P+o9D
od50OKUBpm+z7ynv1856m8SuBhyAVMjxyWgkoUgHOkAqnZHIGj44eCbTQno/ZlCJ
XL1TZdpHPVfcutGz4KzXfA6/zm8jE4aOyc4UlJ87gw2DeJrdkHA72U8ZAoGBAN0+
i7ya/fOgnejitFXD9BTl/+egyBtc0FELDQ1RONG8rZJeYsbcnD9C+JIQqb98Ce2p
00TEsNpX3XKi53YGYwd2y+XL2Jz8xEkWVllm3ROIJw6x1/WokjdOzAW71FFX5QO+
EmldhIxgR9s56hfe+ryVh8HX7Z2GpcAcrOyr6msxAoGBAI7Y96Sp4Tm5/eYziiVc
3nsNUZJ4U6bkLqEXWDt5984XTSmt8hvG/V244tCXraTV8fANGQhgXqLU7i3BrHTk
SzirY8BtkIFYGd4j/myThEt4X+jWDcBhVn8uxrIqnNDoG5CMnDLu0jY/eRAyY+iT
2ZagQbtnDcNL/jaMA5LGGXRo
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/ocsp_ca_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDXBkXMLrrusS+E
7p22IHPEdC2XovIoNSlDjyDYJ8rcPjX0Rus//TdtwGRbbqXZQSMQ+wmlb2tsAAkW
zQKpp5DBbAnU2Ostoqr2gQCXK5i5BKYDid35qbfGhyzB1wG32wQbHDUAy4HZf4Pg
AS2WLVQAUi/TGYRxTMvhJX9cg94tbtFsQDxLI5b89kDyYZkfWhWKZHKywmFkXDJq
9ugOPwF5TdI3Y0To9BX8HFUhYX8B6tuRL8Vl3bEG6KqPG0RkjdqFuswQdCLDQY79
NPtA2OhkI0kksyPdX0ZnRpanA/mnOq/fTxTxgcZVUgTrfXQN7Ql2FQyCmte/JkbW
daWezJGXAgMBAAECggEAKat9BkM+Fbi/sT6+0Ic8eCNdnIfG7vTScNXBczJO9VyW
/yZpO6baQYopyLBKMq6VWZqUtXtAsZbWLBWBwRgIjPtfcmCxPtBJ2miIkUMxHxXg
CEqE+neh9jbG/S+qFRO8GXbfbK6DlP9JsrT3vSU+pKtIulu1F3HfBtxJ8MdbXKlE
kis0919hMzuetFfo2RFG22cdZtkQvVnoxc2f7lMGskbOR13k5pmCFCvPRaIwf6Io
hx0n0WcGyMtvGU13yyBuBQvCquNLYgsUpv4qe5TAXpowx8mHzchvYUOBld+Rum16
wvhdhwSSuPnvJQpJEAiVSsdBJq/E1VqFSe/LevpqDQKBgQD5GO8MhD/8d+rnO3fe
f+nAJQ6muHHHCcaKVnFpcg0qvayVqNbdArv2AfwqejPYfW+X8HjR5lzY/9/jP2Uq
1K8lNGd31NguNv8nzLHZahwZZ1HRd133vYBY8y2kX/C8p6WZ2NgyJrYwa9w3bgFW
f9WWyPAfNwJzHWdKMm7KgypP8wKBgQDc+6FENECVvYRVB2BOkscjzoiQulu83SBa
K5fFn4gPARmM+oESiS2E1mZxrSAVFJvViVwEAVXtL36TjedHvTKl2RCoD7+/gkMs
2DB1xCsjHUytdzSq+WrIDHv6r3aoudDd8LZ4YJZwCVre9Nqoh2qy1n6n5aJhXS0K
HcgUXhpEzQKBgFc+vmtZ3rdkoOfAUmmhz5M253zJWUBnUhydzjcqdSYlLM92RVs/
W+n8JAAUsRgARxemaArMbnSqmhYT3DE2MOoNArhb2iPFq3SbIyeNHK5hG60L6+Ob
gdqlwbSyzbSl20CZTI+0M1eeT5EyfFF5kKuxUTj9oWQERmscYuWXLzi1AoGAUgHr
0gTWJvvC3U80dVRRJL+jvJn8K3WgaPYeh89xTagp1ECun7Nauh5avDr0Wf5g6njk
NfRM8A2dGqMhvmS/I/8PCF932Fk+FqlQKpQXMhvQddt0JzMSZpUDeX+eOHVkxshq
3vdxPLisCWuyrbI7bYzeSe6VOS675TIyKyTU+M0CgYAK31k4Eyv6RwhnzjTQEJJd
qajm+xvmgdvBdvCXwWcSI+vnu/VO5pTLTJaiMCdGIDAaia06oGjPA0tKLzEeb06f
9wAVy99WgXCfhNHTiPF8OPWrjY88pln4rnrUh1sBye7E4Bs0f8NxAYWdBgi8Bnvh
hjK+EoeNgibeyOS/93lLQg==
-----END PRIVATE KEY-----

30
x509/static/ocsp_key.pem Normal file
View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/ocsp_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+QWH0U0sB3jaH
eEoGPUsWU8tAgadlNiZK4KDPaVRjcTbPukYzgaoeqpjQp8A/erGytButj1EywGCU
LYYqGuPO6S0FZgndwc3hHRFZvt2MgaDpLde80ykyh9RpLV5NY0fxe0OK8/3/vl9e
22BvdQlBxYA9GKXDMm8K28CaFdm8MS3Dgy/8xitsjKH0FxYe1c+++ewo/UNNUj1+
RMEVPoqEUOLDG5VOJCfMDVZFz8YOiLLWI7o2E+HguSWLiPuBMjmxAhFujCW4kHg4
iRuezX1CqN6yqqRAjBF9juxP9mn2gyzVkxkzuZOpQlX9QCSsD02swu3jukPaMzuG
K1lk84rtAgMBAAECgf9axtrTj91V+1nK48Ml636k7yUNNExnVUxwB+hj4G/rmatD
j6wgdGN6lvU8CQ/00Nk9b9z5cUXsEGt0BnKSu2x2xPW7LHY2n2fPGdlMqHs3z0YW
wQ9hmyQVOBk2rON3o4MuiNtDX3MiSXM7GSW3ULJnI+21Hso6UGGHEBTDsgHn7jIj
aUxh2er9+ia7Vd9jE7a1mx92bD5sMZ3+latocsmPkk2oUITKq78SLrd1/tAbheia
lJzTdBvDAoXQUY4v3Ib9+uY8AZ8MzNSB8DYMc5wST0CkFCZ3DqE367YpyTQ+m1zM
vg6uDW8Imy1nEJ2jUQ7JATVkSEgxKXN/nxW482ECgYEA7R4+oasSat/et+t7Howk
kOD/FpH6FqtVrOWSZzingsTRA6GBABpSJ5Fu5qYTo3JZvF48pOCbrWjNxog2G4LF
T2CUwvN4O+g4hYy5TKtbJfKMTWjiEc+cPJ7beqcV7wTU8g2dlrg8ZJ89FVKW6l/r
GcM9A89UVpRthE/e2JiORCECgYEAzWfSIU/e1wFFewcC7XJ5TpOiKreF1qNablG9
tX0rsX2kdQN6UcCKwc0POQiNW+ipgg7/7W1Mb/139hE9K3xc4cEP7w+Kte53xV54
JRGFn8WlsGmyECOumE5VED4doaO2LHC1Y6oiAWim9+mNVsHPh5J+9HCiNRhKy9IZ
CMpHbU0CgYEAvHKeCjSAlanIQtmGZvewE+iNMu3fGWcf1yI44Yo4LwimqMERWfiR
NFs0DWEOGIdH5BntDohnkUDK0a7teZ3LnFNAx1NiShI74X++wL0q2pTShq8FhGxA
WjlSaz8hgm2Po7PIe8F+VeXsUObrg+epXDc7Zay/9XNPOqmTjQZpgqECgYBoI8oS
n5cAdSGP9YcTceV05D7k33UY1GtF4WWIfXTIoUXfGatLhY4UIe4k4WQiA/zk9svk
yXRmlyDZ/fWAdaX1w1dbwgp2oPfSdkn9qTuRPLj7jyr7KcwcZiKUgJmvWPxE3cPp
StnA0xlMOfox0UNxneGF9xEWUEGjwtp0bXH3RQKBgQCAi1UrGC0FpH9B+vpz3ryh
OX48k8NaD7q9swL1uX3Hwjv5SpAUTtfeZ+bwVOLmStr3UFetucdVDN4gK+o8uVsb
1m91IAh+nhrCQFopjJNHmA+gTSEd6PBsdrc3BJXLuvGQmWHAuzT34urlll9X5I/6
eRqOo0esuujGA+mzHtvMpw==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,32 @@
# Generated with: openssl rsa -in x509/static/key.pem -passin pass:qwerty -out x509/static/pkcs1_encrypted_key.pem -aes256 -passout pass:qwerty
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI3KLbpDchrtwCAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBA01spDZ/sLkgCOEqMcRuRCBIIE
0BsltB7cxFnjSQXKPM01JIIlvS2Fca7VWye8vb1le5XC7d4+cHo88O14CFeoHboC
8aDMkxpz9/EDW69hFkrB6jgfU3moHJxlarXceoKN0DD5H8Q5RnvKk/4z/1lAMRx9
4jyjQTuQQvv5oeh8tjyPOVuaEpZ2i17ze9lUHsJwCRQda7PMRbbeWcbLewBj1OBQ
a+xBiqS+yH7MA03bfrHpb8/wgPGk5K1+1iSWVuE83Xeo6hHtE/pEn6iiRGAItDge
ABgzH9x8CG2or/45yhTqx21jEdZKvGyQDWQ3KdKol6eegXwDqjAYyURIOVLOwb9Y
epb0w/maqVkj8TjkBw42IkAqH5v+kDDvcrnhCpOr78RQA1r7yvBurB4zsKULz6Lv
wVs58aoxRjPvwgfRBs6xAWK1tLDvPzslEbXTcwwulBBgYoig1cXFga13P1hBuasr
Fr1fAi0jpa7d5I0jIZZotmpnzCPNKDs1O7j4uxO9kBQJV89Vpw4Nsxe9E6B5r9HA
mlXSEj30BVYr83brxHxEPMok9H/OKpQO+O/KCD81A12AM9yw1X7YqMEuVw73SKR/
RB1ZUPd2FB4W7ruxaoVlYMeVhdbe2ZObsTqGJHAedoGcnS3zdIUd1GEOp9DzyWpk
cC8+qshRU5udKfshx1r/HgypncHt5ew8eeW7voWhxssWhqqk+8Kz7UQ+wfFAMe2t
gu5Ppi60aOrAc1BS3U1DZyAjmC0Wie3PLW9Somgg3b5kp8ZKFDD/dgplXr1Kz0LK
CaehizN1EWVwt8qSxjffWQyWgNrPNp9I3cMsTRuKMA2jFnPNrLWwQrjiq3nty9oY
YZeS/W25BoQu7GqQaulzZACRxWe3liP/TBxoA+ym4YgpE/IigzJt7UH9YhTZQRog
GrgP5C3TXnH7TUNx9CFBMOmrbq2z4ig1ecCVUMhoB0c49Y76zZatr4UpL9d9rpJH
0++x/cL79DbtnojDcI6Jn/lcU10Vrtp2eU4T9RguX64j+CFZrTyL8TO5rb8ix9lM
s8H+TSilEDQkYeSCkBa6fjTNe9fVBc3PXVpck2id85p7Cm+YSt2E26jnK5Ij/NzP
50EHzKahfnpH9EnDJeRYtS3eFNBh8z6Epr9/iYkgPlXwA/Dt4TEAPYUXjQXbmhJy
GALLrBW+Kdz8dhWWEYF+sWq+Go0RVS4SUNjdq7M4LeUa3619AgEGijuOIjx7dDjM
V2klj9m2Wkt/EnxHZQOb1PKFLu3bZb8kbNIPTMFnYHwp1cQ2ipQsYjddYAABTdOz
zw6fiA9AYSr72g+NdZgqadVi5KZBvtHxmB3pPrLdaS3fPvrtcVRjMlJ2olHPhanI
AX5BmBNf+SBYpBzi6u4vfKeeu+J74pnrsfQJkV4ngSEqdcNhb+TQjlh25s9vNyMK
LjFEEi6UU7wewdN3P8FSqWfdDETZMVKklqE+K69Sjajixay0YR3Kg/msEC1QdeI4
LHS2qfWgHZGhr77fBRvoj1+Sj+U3PqBmrO9in6XjcBMyLotnSLTIenqyvk6Tb8Rh
D+n8f2DGWHdBhqaw9OVkyKcUioXgS6HV/jNsIk47hLUj9DsQSOWyXgbuSK1/ekAr
kCwkYqe/FTU50qpkd4dYvKja7ShIsn9WVczVEoUwZe/b
-----END ENCRYPTED PRIVATE KEY-----

View File

@ -0,0 +1,32 @@
# Generated with: openssl rsa -in x509/static/trusted_key.pem -passin pass:qwerty -out x509/static/pkcs1_encrypted_trusted_key.pem -aes256 -passout pass:qwerty
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIAgk73pojwy0CAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAGczq7LVH22pU6vE/4Tmc7BIIE
0O09PNfRPxxZB+Kaf6xlhcierFe7IXHIM0tXhKor0bIenbNSStX2vWX4U2Z9aN4O
SN1fRppKAQMaIrC8NtdCC2gMrDFMw0zxRk2DveYkHiLadhcFgcDwjhT1+8uiet1y
amdKvmaPC6oyrTwqsFK/GQBJJD3RkkWySaS6YEyBOD2P4KSO0mko9tuHAlujbMms
zJe94Z6GK+sl1KVVDVj4eIseOgyjycukt9WGu+oF4KADUoxIpjJS4qzut+ZbPcgB
i1Awkrx8BiVT1KPfPz6ZOKgsDNr5CxdIft8iCEpwloURRyfAKU+7HTh1XO0EjXt7
F/FvRTryv7se1ZD8VlJE+A2p95dauiBiYC/JG8ArQTH/Lar5MbkKKWCtmoXQ43PH
PehwD61Au7l/c4IRcbxqLhJui9lcSc//EW6W2tUEpfMsxhF29L4m+3Plt4xhdejc
kOa4hTcUrixIxLY6UydocIwVHID2jdfwhC4ktw/1/oD3dt5glprhxD7dxKMvKwdg
xVCGH/kIeLRB7P/mmAbboIVJ/Shy5pPxcXMSufV0WD9bsA529gghUhyN1InZ8lAx
4u1bZNcZ2er6BAxoMeXHI86N0WMZY4Xzoe85477rJFqjxRwkI2iQ/kvCNOen5Rh8
m5XKfV03FRHHFKuTDhsse1VxYugre0hR0hjUyW9N0uiqhO7A27LS/HxmYEZRTRyr
7wpKOLyWZNgShb2TDmlvMDiWumf8J+0Sayv8dmZ/jQZjrzhvjQ9sysMP7u7WPiYI
jb2hbAZzdYkJfz+V02f+wOvDgKYH7h9VCb6pfTgdHfP7A9PRyRjGw4HkLuf9qcJi
KIlzpaw4cnVSFbStIRvwPerYdKuBqKIHZB6TZNl/Q8HTIH4rReucl6Nry+os9RYS
aYBpwKJwLxvc/gloS+caJ1NKdn4FdOQwjlsguUTNMEUydz/AtjwQ6EVUk/6hN53i
Jdlp3JpQI4N5TIEC7ftKHCM72qDOSJ0X/2s4tkkBooPIWxBH3LRl92A1AblyZ0UG
u1OSfKD5cPSHa+CNK3pvNK5in5bG1+fDncSTlgV8mZaw0ZJ/9p0Z4N/qHuVLngJT
9eufBLdySjwGZOEDSlUXOCl5lE+21eEBqPXerkoMFmhDOU3cb1Ij0Qv3E7hiGRYP
fmFGhOTUtGVoRfevZlxyPlWXi9b3pVF4+8wAfVlCVs2uRUgpjED0WI6ErYM6fxb6
ANPGLeuUiQHhL5EFZ9ZVqGYEi7Vz13sgsGW02b93UUSFpvgVfDu8JkJGjfnmW9sJ
efEm67Fz0c8W30+Eynv35JXBOpNSBmmf2k2YMmvBojtFSA/kA3vdTR6f5VBbtOnV
EkDRtKfOM0FdkyA8go6lD1nJfB+loaIVMOc4h/I8ECnAU7aAUOqsAZS6MjkuDbSc
MqQ9+gWYTV0s8ztflSzJhC4RmMhnq+6h6Hu1NWhYxQDAMsQg0nYiiOBYHIZ0ddKl
TJWsF/atJk7E1IcapJ771aPAUW5bTiv5W141P92bod9pL3+pNsL329Z9KT4OA72X
4kUVfG6yDh/AljttlbnZXCIHehfhU+2yFYQUde8kNiqi41HdtxlHbAFkVbK/NNzT
GB3NdnHo2VUZo9pf0DIiXCJLA9Z58nxnXrty3Ngo1aqa
-----END ENCRYPTED PRIVATE KEY-----

View File

@ -0,0 +1,7 @@
# Generated with: openssl pkcs8 -topk8 -nocrypt -in x509/static/ec_key.pem -out x509/static/pkcs8_encrypted_ec_key.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgRxmpZOL9tO49KR0S
D+dJcJhGJeRoTmWLTCsmlbEDGT+hRANCAAQQ3y6ZMbvix/1xQSn4yqk06ktb+/K8
gRA18rGeB5f4NsGE47VNKrXjWZbcJ/2QELWil4t3D0jJnfMOa4icgHAF
-----END PRIVATE KEY-----

View File

@ -0,0 +1,7 @@
# Generated with: openssl pkcs8 -topk8 -nocrypt -in x509/static/ec_ocsp_ca_key.pem -out x509/static/pkcs8_encrypted_ec_ocsp_ca_key.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgplGlI1Y/2E+bkAD0
u/MGrmT7fiU5g/KQoJswntgUyaahRANCAARrmfc+xdKiRJ3wPmWvSTYBTH/3qDEJ
P61qaugxqkf+xuMa0OYIdGNM1T2UarBZQPBP1hypajq/dKfjUHiqJLYJ
-----END PRIVATE KEY-----

View File

@ -0,0 +1,7 @@
# Generated with: openssl pkcs8 -topk8 -nocrypt -in x509/static/ec_ocsp_key.pem -out x509/static/pkcs8_encrypted_ec_ocsp_key.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgY66ADPLLteZvZCsy
bkZfEqc+bLjoPtsS0PsCkXHd0wGhRANCAARkBEP8cKq3bPEkZv6O0cYQyYut/LO8
vT2PeLBzHP0WZJ2qGAnivN4vIWJ1j7kFZUgvhQtXcnxl08qW+Ktsns0M
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/rollover_ca_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC9fuHlCyJ/Cy3y
1x0bJdyAjHFtISe07DiN2/cPFVaLqIxVjqN9D3hqOGsRsaQTIhLqvzCsup7j9j2K
prmclqEH5YGPIgQTRjfBHhLnqy6p9OjI8Km0QI/WiUwOuhhB/jfKUtWcOJPl8kHL
m1IzMJCAZDIjQr12can1DkvqkbEGPcSIS1Xxj2g7YfAnUBMCB5rndbrPpZEfolJL
YSM3xpoVsdk8YGWszSFHnF15c89DvwwmgZubiBiNzPVhyLU3pbWeBkpXLt8F8Ja7
kYHf9zdLNwR4VQoxN2oYkI9rULPbTVLLYRay1Cadheihd6n0fsUpJGXt+jxj/9kQ
vEv0h1YjAgMBAAECggEAFpFO29VIpXKyZTJjQAFxUknnlESXkv9y+MoSkVRMO1O2
atYS+GjoQVY4wiGy1aiAMj7U0C1lkOaZi7KxdkmmIeeeV2qIq7b4GuK3A6oqY4lM
U+n9e/8YYkd1rGdTTkC1aj4VPIasbn08gsAbuQb2nqPQKMzg/YMp54ptViFFwOVT
rnw4dFttOZjzVUNrUjPIgp39E3bAmMO8qacq7TB8KQVtvmMrnvLKzX/WopydSHtd
9NYct7kd0iwxWsQrvmTrbmeIWRhKNqx7Bjz+PV0CrhJfxgd7R0yaoQdu2usRVQ50
VCBRrG8zY/qttGsdowZxSaOYI+nOfw86nBwok8NhKQKBgQDtq6uu6USz0YonPe1B
/BEqjvog+vu6FvWK01n7UpdSFNbIfDxG8wTm6xxlxEv+xZKtvhKKKliEC+q4xhgL
HUiq01lHWpPOXKaQE07QAcK7R+A2MshbLLCs7dozIOz5Ami8WpjT2PVAokOgNuJV
iO1aPg9ERqHhnfARNugO096M/wKBgQDMHBgHUA+dIAFo3iTWzvRZX3PnMJsk0Tub
X6F1Wx4/MkxMBndMm7lpKBkan9PiTMGGxwZ8NbnP5dLFWb7yxKL59HaryP2/pdKM
IKq4FpRB7CXoIyJvn5ss5NjvWhphyuUAXSWdc4pY1uHMEf9vLhD/VVLu1KSZls58
3DK+jpJi3QKBgCkt1FpC6ndpd9FixmfnX6YLDcWHFvRgI/0Ar5d+8N70413rQJpe
YtwLomjzgONMoiReSWINAjcmxW1sTSAn275VTiOxyug3X1iZL8+UboP6aRua4uIB
NT9RGrw/GS/vvevcmpwh/CRNuP/aYo7FYbKADC8dOdEYh07EP6LKDMZLAoGAFb98
k/Lk5wINBGZ/GGBOyuMPz3dvYHnm1wRWiNGfpG4wkP0zYvdIxzqdiiezhO5WxIya
VUvIM62ySpLodKedEfMJXf55gx0hFQs6BYlqXKfT1itANRKVjzAHKWG5Y+ghhGto
YaF5AURMJNlaFTecWgh2YLpJm4/lCorP4VwBnwUCgYB/nk+zlj2dLG2OG7VcxjFR
GjE0dK+YqYC921q/OOqUkPfe98LwhKsc72Qhq+2P2m8YrRLjwv/RxjsEuU9ieuFq
n1jR/QCUrmwuMg+i1uB0o2MPfZZUn9IRBgCp7cKzAFx2zwK+6jpR2fcbRP0uObhe
e/12vqQex7s2KGXDDGAAPA==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/rollover_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDQbf41+9efMuhz
KEF6ZV+uACaKw62CliaGl2iqZW0FBzR98pGnS/AJiv5PpcSYe8LxUbpry4FkqItg
vbENVAlMEqRKBG9CSFhrgsLD1n7Jgyt5iQ6Tx/GknGXEIqnc0DmRukTOFFm+Qi7c
/Q5lagCXQ1s1+BIxzvrayVGH47QMIsvuKLn1xhvswm/r3g0cQPZVq358zPcBPl+K
OTygsFN2rYjseMHMm3OzGHE8N9yZWvSZui6AkWXDGCFZw7mT0UGC66km3kqKvy6a
s7RnXii86+GawFNBl58GXzononrfYiQiGDwOCnSygzBkq+2dBlRS5g2ja7MT6IiP
krheNdNlAgMBAAECggEAHsmIic/T90uNQ2lYVqx/uBOEne2uhQIJ2cqmprjJpDr+
uXXppuUUJUy3KOurAP0S/BNe7opGaChvQhBzBS17HBYK13YVOxy1ltffTg8ydjCe
bNreYNzhaDfD3ndiUOAfCNQTUr91zCE5i+IDTN6eDLnh0LR+d4YDzup61RBA6aO7
rb5Ki6pzb+axM4pApq4MHKWBTW50YK7tAqwRKf94D9NXY1FDcJXzDii//lrkHL22
0vUx/3yzftA2UztXTFsuw1VnGGeAKz/ozqKH1HlJgQl8mIYorft1lHo/G4E2ceZC
GydBrnXBtHKC/HkVCkKqd1lBXJxHFUh1hWATnasRxwKBgQD71vvAfKpWy6EGnHWr
FEIlW157Z3r92L3iPTjPUmWWGD7I9IokSMPS6f++5Dks83szSkby2KLLJ2t1RzWW
TwiNutGlZp/j87UXZkW78I9ci4Y2GQ+euNPeZ8gkQd438325y5nok/mrLECpicsp
tJjAODz5R5tEsp0EmcCESkkpywKBgQDT3247oEzIcF6JPHzVQOZLTom7HXi/HwbP
r/TclZV8FPHbrbXe9PoAssg4glzYF4nz70GY2zQWomY0vcS4IpdaWDIRdFuHIxbw
/aB0cA+uSdUeV+aKqw9euNrE4Ht/4yI0KvSeWZEAQpGBmyg7eDQe90w50kihpFTr
/FZSjJMRjwKBgF0TBjYMnPO5DEkiOAbDVPLzgsa+5uC8YukjUUSmIi9HxKSGZCum
zOC9ZKyLMmpfji/VisUjtX65kehlKfPkP7gJzIOBmyQnJM2CGdGsxX8hfbeuqWwy
yPLQjlKAGX26OsQY8EfZsJNHpppB99jxCuc3oalLgqHwFUHnBRSfU8zjAoGAXMvf
W/45oxCUV0dG5aAnPZSIfovJ9ut/8DcA6Bwb/NyvkafjoGNrnCKxzw5J29tzcIO6
F1jq138JhNAY+Q0tfURjqYFtFSMpSSPMwzLRq2RrE38sWk/Ry4rrRo+Lh9fTg0XN
Hg3clGCTmlB6rpFXQrjNigWwChwPlcxPgphPUcECgYEAgkfke2ZomSsfoKjD6U9Q
qP06emWigrgroGWNnSLMq6eFYZtkyqa+DtcJglhwcJHKxd/5dGDB+mHiAEqWtsxK
P0UP5SyitY2OORTldUZdm9LXji9q0CIZ08bhGT0BRIkwute4mGuyIKd0rA6g+na3
ojrmELTDxiYBCZ5ONtCI/jA=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/trusted_ca_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCtW/NTl/RS3pAT
PyuPjCu4YE7lQuQ8JoLAMZBPftsyILi1+fylLizHLSXkhi2Kch2BJO1mijptOiQ3
nFjYRYIwHzqg4SPMM6Dr4ocH5MgLNP42X4VthjRuifeSClGgO1JNg+4MLckBRT7W
Cy5p2kdFSjhexjMauDNj/WeLOy+aNeEUsB1CrLbBY7XcJIjFsL/whdyvnvdfTYGM
XFouCIt7rwyub45TBB07BVDSQksQERY9GsXi1a4hk9ogvg3bKtjQDji4RsdtGeSJ
6HcA7y9/xsbbhYQTjQ3DzvZT07Q7dDuM3B2RNpwMOm3M+aJJchlaaSOjADTSasK3
w2Siy/tJAgMBAAECggEAAcE1S/Or3qTdWuWpJiTjbdRnulFXzMhZlFBMHiVNf2Z3
iCm6HN2fkfqLFQC4rySP17+WJ0oNUlhtGUdJo8mg5aXw/OhRVzpv+3ob3e5fifzt
+PA1Ai3dyrYRy1+POPPnntyGpKtX+JRkfqUkwcSIWAD9GqbDpTsXXO5goQA5Suk3
JAVv7kHr3cuaPUmcKj7V8XjhPZM/zbQ33sLO0mpeWrX3BQCjxxcuPUJajwGNPQtK
ZY5HqXywNx837FyBctZGHjGElmjcPuGpEEOtv3zJj2r6/tnFelq0MWXzWus9GnWe
78/8c8PT+YeAUQZSPudNxnjCiuBI5wrsmgqRUdEZywKBgQDi7DPotRRjPliWlw9v
5UpMdDai0ubFD3eU+NvWEp13PwXPGvaqfJbUGUByM9SP02PSGVq11JgCIVGcYqyb
lgcRIAQAoPpLf6UOBPzVbBlA8vSwQFxMja5wO8GV6wER36czDgMFg5S0o49zYCbG
CugbhyjqC29+P3pPPFWpWmRvPwKBgQDDkrE0XiEc9YHOL/FV6DNv+ekf1IlaxLRg
P6l5TEX7bM4PzW+aQmOe6UBnyIiYk/ANbSvlsd8ups6WOWVKf69/uhqfUupRobAR
12m16mmi8Q90a9akVIo/N+RJ/nd+jq7OcN/iF/GrH4vOXZT7XJDzoULdou8LdZgF
SfdPIhd7dwKBgB6SDagzBO0d0BdxgF3luO211kp3OSmhHM4P/KXJWjdfYSv2iPaM
1FD8mecIvoElzFPYoJTQcC4RSQpVbMWFH6yZ8JAZH78eEiFiYKFr77cFRBuegBC8
IZzzH/BPeZRr2f2RzKxofpcbVc8ITBDwFTboLYXiRoHukU6tZSjsiY1HAoGAbgUj
8xXRAv2J3HhUB8Psy92HLATgkFOANXUa3cXuyJZZBcLIObuHV2pYdQn27f6rWKJF
w53gs9na9d+r/9D85ZnISEDY2Ltg1Wida11HuAZsb04LHb8BVrcWkhm5F1UlObV9
/S8DIQVKHPnASfe1A5mAiDaUy5mHv9Hwcm/3TdkCgYAFSKVUtezvxm2vJT2hLtOg
9HjrP/pdOG5eL1SZSTX0kEZBPmrrkRuEigYI2UsvI4NILLec40/FsWyfdwJeyPvR
Ays0RrkuSGbb+GM3rB6XVS2CyC30g+FMml5SyeJAis4sA7lNEzzwKsitVjzCvlqq
6Q3/kv/VHo0Mhd3wZKFDYg==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
# Generated with: openssl genrsa -out x509/static/trusted_key.pem 2048
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCvpTTts3ejYVgy
HTOFRDDekFYgjEPpN5/Jel80AOukwPxjA3VRQDV3qMVO5jNg59KLgHrErm+QnpOg
rfjgaYfMRY7YUUHtl6zbvdTVbPnJwEkAmN3+UPnfa6AAwk1R5E/gLgE4qLOx1gIh
OOq4WCY6GpIMX5DbS6DxWpwtf4DZ2xH01k/pxtFEnzAisQE1mNyKIbfqqq8VAjqV
hBHXiHTHxIdGppmId6Fa0bv4TYhB7MYuUs2cldxkJquQURODnnmEaP98uC82eMSh
/PZ08HfsiHzD/YFKT934rKmfsJ+wxtmiJJEkTK8havSbcHyjsHBsQR04Rzm9h6NO
B7pyXOexAgMBAAECggEAPSZ+uVzYg6SR4IyjEbwOaYYFvjonMIxBkJMOjxvc7lST
6eLb1shMdRbobpIdhBjhh9jYpR330Hks+21mLrb+5MK4ux37Hn1GXJCIBy/z/OX5
ZIBUFUTa4YpmP61l3uNmXa2WlkPBn+Hahvd6XGiwEl2KyE0DMR3w7+Y0ZnC0CuQy
GhH3F39wHOSYXozLObX4nxmmfXq1O29Pc6IaXklckjzVir+2++LcZqykBYxGfSnE
gaMAm109HvRtXH3GjVNnsOut6y/sfjW3xwbMEGnJTwcTRKmRe6DQ7Zojfa20/zDY
it+ETuhy4u9ncsIHKOldHhHdXJ+eNoHfoAg81qZekwKBgQDs7o9JCaKBkeLtSQxj
CYgQrsGOYU6p6D8jOcyF8TtBaB1z+SQ760mj5d46bqBdwWoqwvQT9vGZgg3j0HLW
i/1iFIeFWbqAZkNjKcvReGpMP/0e6wGQGlrExkr2p6w2DQJi5xm96b82eXfgrOSe
lx7GBfDK3iRimgl80BTHjgzH9wKBgQC9x/pZD+YzuR9xSyRo9iJ8h/U2cZOYiqwu
bsdwhMCzUEm45xc0+WR+TP2p2VWx42IUHQ3+sjRArpGSGiosnmLh4WwpwLp3vRqr
+nuZW33PKuef+x34emSP+Nyfs1rCacGmjC/mP1RWBXhcZ8AJFAqN/dKTKg2gE0ja
ptvGgzlzlwKBgQDkBEYzFSmmpp6Mm7NnEII5A+XUv4Lz80XoAbT55omPTcKinM+p
NqvdJtiyxUpiUER7OLmrCQnEISx65V3PalQE8xrlU9Avx7rskQnM4qTyEtbnzWTo
qORX4Tm9nOoX7ncwdZYJdg4GP+oFeH5gvbDpBEiTBCxiFDozOxH0ZpmYSwKBgQC5
xIGrImQM5z3+8TXvxFcXnSILq/t1CvDl9qwk2N2j6IhxhUtzIFgdRZHb65D1swUz
eQlU8e0yD28RG6mCyXszbiwpZq1gPexYwbSw9hzdaDsYn3/D1VKQl2KmtLK3sTvM
olbUw9Ly7SHXGfuhJ0v5l6bDRRvXQGlFFqX02EipewKBgQCfE9IHCmCiq80eeDZ9
Nnk4bakLyYPZL4Cc21Mh+wUfM2FTp/8IrQwToBkUR6ueidI4JTD/hF6YHfxKgcVd
ndcZ+uhvNb7x5v84NLiEvxWZ1sKt88ZYwpHA84ih7aEreMdzp99i4Q3AqLvS4isx
4vlJ5KzmUu3J+nYM1iRQkNm5DQ==
-----END PRIVATE KEY-----