Ceremony: remove support for delegated CRL and OCSP signers (#8309)
Delegated CRL Signers are forbidden by the Baseline Requirements, and we haven't used Delegated OCSP Responders since 2020. This code is dead, and creates unnecessary complexity, so remove it. At the same time, improve our README to reflect these changes and resolve several formatting lint warnings.
This commit is contained in:
parent
b9dbcdbba2
commit
d5bb88b975
|
|
@ -1,21 +1,20 @@
|
||||||
# `ceremony`
|
# `ceremony`
|
||||||
|
|
||||||
```
|
```sh
|
||||||
ceremony --config path/to/config.yml
|
ceremony --config path/to/config.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
`ceremony` is a tool designed for Certificate Authority specific key and certificate ceremonies. The main design principle is that unlike most ceremony tooling there is a single user input, a configuration file, which is required to complete a root, intermediate, or key ceremony. The goal is to make ceremonies as simple as possible and allow for simple verification of a single file, instead of verification of a large number of independent commands.
|
`ceremony` is a tool designed for Certificate Authority specific key and certificate ceremonies. The main design principle is that unlike most ceremony tooling there is a single user input, a configuration file, which is required to complete a root, intermediate, or key ceremony. The goal is to make ceremonies as simple as possible and allow for simple verification of a single file, instead of verification of a large number of independent commands.
|
||||||
|
|
||||||
`ceremony` has these modes:
|
`ceremony` has these modes:
|
||||||
* `root` - generates a signing key on HSM and creates a self-signed root certificate that uses the generated key, outputting a PEM public key, and a PEM certificate. After generating such a root for public trust purposes, it should be submitted to [as many root programs as is possible/practical](https://github.com/daknob/root-programs).
|
|
||||||
* `intermediate` - creates a intermediate certificate and signs it using a signing key already on a HSM, outputting a PEM certificate
|
- `root`: generates a signing key on HSM and creates a self-signed root certificate that uses the generated key, outputting a PEM public key, and a PEM certificate. After generating such a root for public trust purposes, it should be submitted to [as many root programs as is possible/practical](https://github.com/daknob/root-programs).
|
||||||
* `cross-csr` - creates a CSR for signing by a third party, outputting a PEM CSR.
|
- `intermediate`: creates a intermediate certificate and signs it using a signing key already on a HSM, outputting a PEM certificate
|
||||||
* `cross-certificate` - issues a certificate for one root, signed by another root. This is distinct from an intermediate because there is no path length constraint and there are no EKUs.
|
- `cross-csr`: creates a CSR for signing by a third party, outputting a PEM CSR.
|
||||||
* `ocsp-signer` - creates a delegated OCSP signing certificate and signs it using a signing key already on a HSM, outputting a PEM certificate
|
- `cross-certificate`: issues a certificate for one root, signed by another root. This is distinct from an intermediate because there is no path length constraint and there are no EKUs.
|
||||||
* `crl-signer` - creates a delegated CRL signing certificate and signs it using a signing key already on a HSM, outputting a PEM certificate
|
- `key`: generates a signing key on HSM, outputting a PEM public key
|
||||||
* `key` - generates a signing key on HSM, outputting a PEM public key
|
- `ocsp-response`: creates a OCSP response for the provided certificate and signs it using a signing key already on a HSM, outputting a base64 encoded response
|
||||||
* `ocsp-response` - creates a OCSP response for the provided certificate and signs it using a signing key already on a HSM, outputting a base64 encoded response
|
- `crl`: creates a CRL with the IDP extension and `onlyContainsCACerts = true` from the provided profile and signs it using a signing key already on a HSM, outputting a PEM CRL
|
||||||
* `crl` - creates a CRL with the IDP extension and `onlyContainsCACerts = true` from the provided profile and signs it using a signing key already on a HSM, outputting a PEM CRL
|
|
||||||
|
|
||||||
These modes are set in the `ceremony-type` field of the configuration file.
|
These modes are set in the `ceremony-type` field of the configuration file.
|
||||||
|
|
||||||
|
|
@ -29,23 +28,29 @@ This tool always generates key pairs such that the public and private key are bo
|
||||||
|
|
||||||
- `ceremony-type`: string describing the ceremony type, `root`.
|
- `ceremony-type`: string describing the ceremony type, `root`.
|
||||||
- `pkcs11`: object containing PKCS#11 related fields.
|
- `pkcs11`: object containing PKCS#11 related fields.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
||||||
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
||||||
| `store-key-in-slot` | Specifies which HSM object slot the generated signing key should be stored in. |
|
| `store-key-in-slot` | Specifies which HSM object slot the generated signing key should be stored in. |
|
||||||
| `store-key-with-label` | Specifies the HSM object label for the generated signing key. Both public and private key objects are stored with this label. |
|
| `store-key-with-label` | Specifies the HSM object label for the generated signing key. Both public and private key objects are stored with this label. |
|
||||||
|
|
||||||
- `key`: object containing key generation related fields.
|
- `key`: object containing key generation related fields.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `type` | Specifies the type of key to be generated, either `rsa` or `ecdsa`. If `rsa` the generated key will have an exponent of 65537 and a modulus length specified by `rsa-mod-length`. If `ecdsa` the curve is specified by `ecdsa-curve`. |
|
| `type` | Specifies the type of key to be generated, either `rsa` or `ecdsa`. If `rsa` the generated key will have an exponent of 65537 and a modulus length specified by `rsa-mod-length`. If `ecdsa` the curve is specified by `ecdsa-curve`. |
|
||||||
| `ecdsa-curve` | Specifies the ECDSA curve to use when generating key, either `P-224`, `P-256`, `P-384`, or `P-521`. |
|
| `ecdsa-curve` | Specifies the ECDSA curve to use when generating key, either `P-224`, `P-256`, `P-384`, or `P-521`. |
|
||||||
| `rsa-mod-length` | Specifies the length of the RSA modulus, either `2048` or `4096`.
|
| `rsa-mod-length` | Specifies the length of the RSA modulus, either `2048` or `4096`. |
|
||||||
|
|
||||||
- `outputs`: object containing paths to write outputs.
|
- `outputs`: object containing paths to write outputs.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `public-key-path` | Path to store generated PEM public key. |
|
| `public-key-path` | Path to store generated PEM public key. |
|
||||||
| `certificate-path` | Path to store signed PEM certificate. |
|
| `certificate-path` | Path to store signed PEM certificate. |
|
||||||
|
|
||||||
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format).
|
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
@ -76,25 +81,31 @@ certificate-profile:
|
||||||
|
|
||||||
This config generates a ECDSA P-384 key in the HSM with the object label `root signing key` and uses this key to sign a self-signed certificate. The public key for the key generated is written to `/home/user/root-signing-pub.pem` and the certificate is written to `/home/user/root-cert.pem`.
|
This config generates a ECDSA P-384 key in the HSM with the object label `root signing key` and uses this key to sign a self-signed certificate. The public key for the key generated is written to `/home/user/root-signing-pub.pem` and the certificate is written to `/home/user/root-cert.pem`.
|
||||||
|
|
||||||
### Intermediate or Cross-Certificate ceremony
|
### Intermediate ceremony
|
||||||
|
|
||||||
- `ceremony-type`: string describing the ceremony type, `intermediate` or `cross-certificate`.
|
- `ceremony-type`: string describing the ceremony type, `intermediate`.
|
||||||
- `pkcs11`: object containing PKCS#11 related fields.
|
- `pkcs11`: object containing PKCS#11 related fields.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
||||||
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
||||||
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
||||||
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
||||||
|
|
||||||
- `inputs`: object containing paths for inputs
|
- `inputs`: object containing paths for inputs
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `public-key-path` | Path to PEM subject public key for certificate. |
|
|
||||||
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
||||||
|
| `public-key-path` | Path to PEM subject public key for certificate. |
|
||||||
|
|
||||||
- `outputs`: object containing paths to write outputs.
|
- `outputs`: object containing paths to write outputs.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `certificate-path` | Path to store signed PEM certificate. |
|
| `certificate-path` | Path to store signed PEM certificate. |
|
||||||
|
|
||||||
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format).
|
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
@ -106,8 +117,8 @@ pkcs11:
|
||||||
signing-key-slot: 0
|
signing-key-slot: 0
|
||||||
signing-key-label: root signing key
|
signing-key-label: root signing key
|
||||||
inputs:
|
inputs:
|
||||||
public-key-path: /home/user/intermediate-signing-pub.pem
|
|
||||||
issuer-certificate-path: /home/user/root-cert.pem
|
issuer-certificate-path: /home/user/root-cert.pem
|
||||||
|
public-key-path: /home/user/intermediate-signing-pub.pem
|
||||||
outputs:
|
outputs:
|
||||||
certificate-path: /home/user/intermediate-cert.pem
|
certificate-path: /home/user/intermediate-cert.pem
|
||||||
certificate-profile:
|
certificate-profile:
|
||||||
|
|
@ -131,26 +142,95 @@ certificate-profile:
|
||||||
|
|
||||||
This config generates an intermediate certificate signed by a key in the HSM, identified by the object label `root signing key` and the object ID `ffff`. The subject key used is taken from `/home/user/intermediate-signing-pub.pem` and the issuer is `/home/user/root-cert.pem`, the resulting certificate is written to `/home/user/intermediate-cert.pem`.
|
This config generates an intermediate certificate signed by a key in the HSM, identified by the object label `root signing key` and the object ID `ffff`. The subject key used is taken from `/home/user/intermediate-signing-pub.pem` and the issuer is `/home/user/root-cert.pem`, the resulting certificate is written to `/home/user/intermediate-cert.pem`.
|
||||||
|
|
||||||
Note: Intermediate certificates always include the extended key usages id-kp-serverAuth as required by 7.1.2.2.g of the CABF Baseline Requirements. Since we also include id-kp-clientAuth in end-entity certificates in boulder we also include it in intermediates, if this changes we may remove this inclusion.
|
Note: Intermediate certificates always include the extended key usages id-kp-serverAuth as required by 7.1.2.2.g of the CABF Baseline Requirements.
|
||||||
|
|
||||||
### Cross-CSR ceremony
|
### Cross-Certificate ceremony
|
||||||
|
|
||||||
- `ceremony-type`: string describing the ceremony type, `cross-csr`.
|
- `ceremony-type`: string describing the ceremony type, `cross-certificate`.
|
||||||
- `pkcs11`: object containing PKCS#11 related fields.
|
- `pkcs11`: object containing PKCS#11 related fields.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
||||||
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
||||||
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
||||||
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
||||||
|
|
||||||
- `inputs`: object containing paths for inputs
|
- `inputs`: object containing paths for inputs
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
||||||
|
| `public-key-path` | Path to PEM subject public key for certificate. |
|
||||||
|
| `certificate-to-cross-sign-path` | Path to PEM self-signed certificate that this ceremony is a cross-sign of. |
|
||||||
|
|
||||||
|
- `outputs`: object containing paths to write outputs.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `certificate-path` | Path to store signed PEM certificate. |
|
||||||
|
|
||||||
|
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ceremony-type: cross-certificate
|
||||||
|
pkcs11:
|
||||||
|
module: /usr/lib/opensc-pkcs11.so
|
||||||
|
signing-key-slot: 0
|
||||||
|
signing-key-label: root signing key
|
||||||
|
inputs:
|
||||||
|
issuer-certificate-path: /home/user/root-cert.pem
|
||||||
|
public-key-path: /home/user/root-signing-pub-2.pem
|
||||||
|
certificate-to-cross-sign-path: /home/user/root-cert-2.pem
|
||||||
|
outputs:
|
||||||
|
certificate-path: /home/user/root-cert-2-cross.pem
|
||||||
|
certificate-profile:
|
||||||
|
signature-algorithm: ECDSAWithSHA384
|
||||||
|
common-name: CA root 2
|
||||||
|
organization: good guys
|
||||||
|
country: US
|
||||||
|
not-before: 2020-01-01 12:00:00
|
||||||
|
not-after: 2040-01-01 12:00:00
|
||||||
|
ocsp-url: http://good-guys.com/ocsp
|
||||||
|
crl-url: http://good-guys.com/crl
|
||||||
|
issuer-url: http://good-guys.com/root
|
||||||
|
policies:
|
||||||
|
- oid: 1.2.3
|
||||||
|
- oid: 4.5.6
|
||||||
|
key-usages:
|
||||||
|
- Digital Signature
|
||||||
|
- Cert Sign
|
||||||
|
- CRL Sign
|
||||||
|
```
|
||||||
|
|
||||||
|
This config generates a cross-sign of the already-created "CA root 2", issued from the similarly-already-created "CA root". The subject key used is taken from `/home/user/root-signing-pub-2.pem`. The EKUs and Subject Key Identifier are taken from `/home/user/root-cert-2-cross.pem`. The issuer is `/home/user/root-cert.pem`, and the Issuer and Authority Key Identifier fields are taken from that cert. The resulting certificate is written to `/home/user/root-cert-2-cross.pem`.
|
||||||
|
|
||||||
|
### Cross-CSR ceremony
|
||||||
|
|
||||||
|
- `ceremony-type`: string describing the ceremony type, `cross-csr`.
|
||||||
|
- `pkcs11`: object containing PKCS#11 related fields.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
||||||
|
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
||||||
|
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
||||||
|
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
||||||
|
|
||||||
|
- `inputs`: object containing paths for inputs
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `public-key-path` | Path to PEM subject public key for certificate. |
|
| `public-key-path` | Path to PEM subject public key for certificate. |
|
||||||
|
|
||||||
- `outputs`: object containing paths to write outputs.
|
- `outputs`: object containing paths to write outputs.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `csr-path` | Path to store PEM CSR for cross-signing, optional. |
|
| `csr-path` | Path to store PEM CSR for cross-signing, optional. |
|
||||||
|
|
||||||
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format). Should only include Subject related fields `common-name`, `organization`, `country`.
|
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format). Should only include Subject related fields `common-name`, `organization`, `country`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
@ -173,119 +253,28 @@ certificate-profile:
|
||||||
|
|
||||||
This config generates a CSR signed by a key in the HSM, identified by the object label `intermediate signing key`, and writes it to `/home/user/csr.pem`.
|
This config generates a CSR signed by a key in the HSM, identified by the object label `intermediate signing key`, and writes it to `/home/user/csr.pem`.
|
||||||
|
|
||||||
### OCSP Signing Certificate ceremony
|
|
||||||
|
|
||||||
- `ceremony-type`: string describing the ceremony type, `ocsp-signer`.
|
|
||||||
- `pkcs11`: object containing PKCS#11 related fields.
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
|
||||||
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
|
||||||
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
|
||||||
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
|
||||||
- `inputs`: object containing paths for inputs
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `public-key-path` | Path to PEM subject public key for certificate. |
|
|
||||||
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
|
||||||
- `outputs`: object containing paths to write outputs.
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `certificate-path` | Path to store signed PEM certificate. |
|
|
||||||
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format). The key-usages, ocsp-url, and crl-url fields must not be set.
|
|
||||||
|
|
||||||
When generating an OCSP signing certificate the key usages field will be set to just Digital Signature and an EKU extension will be included with the id-kp-OCSPSigning usage. Additionally an id-pkix-ocsp-nocheck extension will be included in the certificate.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
ceremony-type: ocsp-signer
|
|
||||||
pkcs11:
|
|
||||||
module: /usr/lib/opensc-pkcs11.so
|
|
||||||
signing-key-slot: 0
|
|
||||||
signing-key-label: intermediate signing key
|
|
||||||
inputs:
|
|
||||||
public-key-path: /home/user/ocsp-signer-signing-pub.pem
|
|
||||||
issuer-certificate-path: /home/user/intermediate-cert.pem
|
|
||||||
outputs:
|
|
||||||
certificate-path: /home/user/ocsp-signer-cert.pem
|
|
||||||
certificate-profile:
|
|
||||||
signature-algorithm: ECDSAWithSHA384
|
|
||||||
common-name: CA OCSP signer
|
|
||||||
organization: good guys
|
|
||||||
country: US
|
|
||||||
not-before: 2020-01-01 12:00:00
|
|
||||||
not-after: 2040-01-01 12:00:00
|
|
||||||
issuer-url: http://good-guys.com/root
|
|
||||||
```
|
|
||||||
|
|
||||||
This config generates a delegated OCSP signing certificate signed by a key in the HSM, identified by the object label `intermediate signing key` and the object ID `ffff`. The subject key used is taken from `/home/user/ocsp-signer-signing-pub.pem` and the issuer is `/home/user/intermediate-cert.pem`, the resulting certificate is written to `/home/user/ocsp-signer-cert.pem`.
|
|
||||||
|
|
||||||
### CRL Signing Certificate ceremony
|
|
||||||
|
|
||||||
- `ceremony-type`: string describing the ceremony type, `crl-signer`.
|
|
||||||
- `pkcs11`: object containing PKCS#11 related fields.
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
|
||||||
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
|
||||||
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
|
||||||
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
|
||||||
- `inputs`: object containing paths for inputs
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `public-key-path` | Path to PEM subject public key for certificate. |
|
|
||||||
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
|
||||||
- `outputs`: object containing paths to write outputs.
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `certificate-path` | Path to store signed PEM certificate. |
|
|
||||||
- `certificate-profile`: object containing profile for certificate to generate. Fields are documented [below](#certificate-profile-format). The key-usages, ocsp-url, and crl-url fields must not be set.
|
|
||||||
|
|
||||||
When generating a CRL signing certificate the key usages field will be set to just CRL Sign.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
ceremony-type: crl-signer
|
|
||||||
pkcs11:
|
|
||||||
module: /usr/lib/opensc-pkcs11.so
|
|
||||||
signing-key-slot: 0
|
|
||||||
signing-key-label: intermediate signing key
|
|
||||||
inputs:
|
|
||||||
public-key-path: /home/user/crl-signer-signing-pub.pem
|
|
||||||
issuer-certificate-path: /home/user/intermediate-cert.pem
|
|
||||||
outputs:
|
|
||||||
certificate-path: /home/user/crl-signer-cert.pem
|
|
||||||
certificate-profile:
|
|
||||||
signature-algorithm: ECDSAWithSHA384
|
|
||||||
common-name: CA CRL signer
|
|
||||||
organization: good guys
|
|
||||||
country: US
|
|
||||||
not-before: 2020-01-01 12:00:00
|
|
||||||
not-after: 2040-01-01 12:00:00
|
|
||||||
issuer-url: http://good-guys.com/root
|
|
||||||
```
|
|
||||||
|
|
||||||
This config generates a delegated CRL signing certificate signed by a key in the HSM, identified by the object label `intermediate signing key` and the object ID `ffff`. The subject key used is taken from `/home/user/crl-signer-signing-pub.pem` and the issuer is `/home/user/intermediate-cert.pem`, the resulting certificate is written to `/home/user/crl-signer-cert.pem`.
|
|
||||||
|
|
||||||
### Key ceremony
|
### Key ceremony
|
||||||
|
|
||||||
- `ceremony-type`: string describing the ceremony type, `key`.
|
- `ceremony-type`: string describing the ceremony type, `key`.
|
||||||
- `pkcs11`: object containing PKCS#11 related fields.
|
- `pkcs11`: object containing PKCS#11 related fields.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
||||||
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
||||||
| `store-key-in-slot` | Specifies which HSM object slot the generated signing key should be stored in. |
|
| `store-key-in-slot` | Specifies which HSM object slot the generated signing key should be stored in. |
|
||||||
| `store-key-with-label` | Specifies the HSM object label for the generated signing key. Both public and private key objects are stored with this label. |
|
| `store-key-with-label` | Specifies the HSM object label for the generated signing key. Both public and private key objects are stored with this label. |
|
||||||
|
|
||||||
- `key`: object containing key generation related fields.
|
- `key`: object containing key generation related fields.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `type` | Specifies the type of key to be generated, either `rsa` or `ecdsa`. If `rsa` the generated key will have an exponent of 65537 and a modulus length specified by `rsa-mod-length`. If `ecdsa` the curve is specified by `ecdsa-curve`. |
|
| `type` | Specifies the type of key to be generated, either `rsa` or `ecdsa`. If `rsa` the generated key will have an exponent of 65537 and a modulus length specified by `rsa-mod-length`. If `ecdsa` the curve is specified by `ecdsa-curve`. |
|
||||||
| `ecdsa-curve` | Specifies the ECDSA curve to use when generating key, either `P-224`, `P-256`, `P-384`, or `P-521`. |
|
| `ecdsa-curve` | Specifies the ECDSA curve to use when generating key, either `P-224`, `P-256`, `P-384`, or `P-521`. |
|
||||||
| `rsa-mod-length` | Specifies the length of the RSA modulus, either `2048` or `4096`.
|
| `rsa-mod-length` | Specifies the length of the RSA modulus, either `2048` or `4096`. |
|
||||||
|
|
||||||
- `outputs`: object containing paths to write outputs.
|
- `outputs`: object containing paths to write outputs.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `public-key-path` | Path to store generated PEM public key. |
|
| `public-key-path` | Path to store generated PEM public key. |
|
||||||
|
|
@ -311,23 +300,30 @@ This config generates an ECDSA P-384 key in the HSM with the object label `inter
|
||||||
|
|
||||||
- `ceremony-type`: string describing the ceremony type, `ocsp-response`.
|
- `ceremony-type`: string describing the ceremony type, `ocsp-response`.
|
||||||
- `pkcs11`: object containing PKCS#11 related fields.
|
- `pkcs11`: object containing PKCS#11 related fields.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
||||||
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
||||||
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
||||||
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
||||||
|
|
||||||
- `inputs`: object containing paths for inputs
|
- `inputs`: object containing paths for inputs
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `certificate-path` | Path to PEM certificate to create a response for. |
|
| `certificate-path` | Path to PEM certificate to create a response for. |
|
||||||
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
||||||
| `delegated-issuer-certificate-path` | Path to PEM delegated issuer certificate, if one is being used. |
|
| `delegated-issuer-certificate-path` | Path to PEM delegated issuer certificate, if one is being used. |
|
||||||
|
|
||||||
- `outputs`: object containing paths to write outputs.
|
- `outputs`: object containing paths to write outputs.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `response-path` | Path to store signed base64 encoded response. |
|
| `response-path` | Path to store signed base64 encoded response. |
|
||||||
|
|
||||||
- `ocsp-profile`: object containing profile for the OCSP response.
|
- `ocsp-profile`: object containing profile for the OCSP response.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `this-update` | Specifies the OCSP response thisUpdate date, in the format `2006-01-02 15:04:05`. The time will be interpreted as UTC. |
|
| `this-update` | Specifies the OCSP response thisUpdate date, in the format `2006-01-02 15:04:05`. The time will be interpreted as UTC. |
|
||||||
|
|
@ -359,21 +355,28 @@ This config generates a OCSP response signed by a key in the HSM, identified by
|
||||||
|
|
||||||
- `ceremony-type`: string describing the ceremony type, `crl`.
|
- `ceremony-type`: string describing the ceremony type, `crl`.
|
||||||
- `pkcs11`: object containing PKCS#11 related fields.
|
- `pkcs11`: object containing PKCS#11 related fields.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
| `module` | Path to the PKCS#11 module to use to communicate with a HSM. |
|
||||||
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
| `pin` | Specifies the login PIN, should only be provided if the HSM device requires one to interact with the slot. |
|
||||||
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
| `signing-key-slot` | Specifies which HSM object slot the signing key is in. |
|
||||||
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
| `signing-key-label` | Specifies the HSM object label for the signing keypair's public key. |
|
||||||
|
|
||||||
- `inputs`: object containing paths for inputs
|
- `inputs`: object containing paths for inputs
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
| `issuer-certificate-path` | Path to PEM issuer certificate. |
|
||||||
|
|
||||||
- `outputs`: object containing paths to write outputs.
|
- `outputs`: object containing paths to write outputs.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `crl-path` | Path to store signed PEM CRL. |
|
| `crl-path` | Path to store signed PEM CRL. |
|
||||||
|
|
||||||
- `crl-profile`: object containing profile for the CRL.
|
- `crl-profile`: object containing profile for the CRL.
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `this-update` | Specifies the CRL thisUpdate date, in the format `2006-01-02 15:04:05`. The time will be interpreted as UTC. |
|
| `this-update` | Specifies the CRL thisUpdate date, in the format `2006-01-02 15:04:05`. The time will be interpreted as UTC. |
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,6 @@ type certType int
|
||||||
const (
|
const (
|
||||||
rootCert certType = iota
|
rootCert certType = iota
|
||||||
intermediateCert
|
intermediateCert
|
||||||
ocspCert
|
|
||||||
crlCert
|
|
||||||
crossCert
|
crossCert
|
||||||
requestCert
|
requestCert
|
||||||
)
|
)
|
||||||
|
|
@ -153,23 +151,12 @@ func (profile *certProfile) verifyProfile(ct certType) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BR 7.1.2.10.5 CA Certificate Certificate Policies
|
// BR 7.1.2.10.5 CA Certificate Certificate Policies
|
||||||
// OID 2.23.140.1.2.1 is an anyPolicy
|
// OID 2.23.140.1.2.1 is CABF BRs Domain Validated
|
||||||
if len(profile.Policies) != 1 || profile.Policies[0].OID != "2.23.140.1.2.1" {
|
if len(profile.Policies) != 1 || profile.Policies[0].OID != "2.23.140.1.2.1" {
|
||||||
return errors.New("policy should be exactly BRs domain-validated for subordinate CAs")
|
return errors.New("policy should be exactly BRs domain-validated for subordinate CAs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ct == ocspCert || ct == crlCert {
|
|
||||||
if len(profile.KeyUsages) != 0 {
|
|
||||||
return errors.New("key-usages cannot be set for a delegated signer")
|
|
||||||
}
|
|
||||||
if profile.CRLURL != "" {
|
|
||||||
return errors.New("crl-url cannot be set for a delegated signer")
|
|
||||||
}
|
|
||||||
if profile.OCSPURL != "" {
|
|
||||||
return errors.New("ocsp-url cannot be set for a delegated signer")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,8 +181,6 @@ var stringToKeyUsage = map[string]x509.KeyUsage{
|
||||||
"Cert Sign": x509.KeyUsageCertSign,
|
"Cert Sign": x509.KeyUsageCertSign,
|
||||||
}
|
}
|
||||||
|
|
||||||
var oidOCSPNoCheck = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 5}
|
|
||||||
|
|
||||||
func generateSKID(pk []byte) ([]byte, error) {
|
func generateSKID(pk []byte) ([]byte, error) {
|
||||||
var pkixPublicKey struct {
|
var pkixPublicKey struct {
|
||||||
Algo pkix.AlgorithmIdentifier
|
Algo pkix.AlgorithmIdentifier
|
||||||
|
|
@ -252,11 +237,6 @@ func makeTemplate(randReader io.Reader, profile *certProfile, pubKey []byte, tbc
|
||||||
}
|
}
|
||||||
ku |= kuBit
|
ku |= kuBit
|
||||||
}
|
}
|
||||||
if ct == ocspCert {
|
|
||||||
ku = x509.KeyUsageDigitalSignature
|
|
||||||
} else if ct == crlCert {
|
|
||||||
ku = x509.KeyUsageCRLSign
|
|
||||||
}
|
|
||||||
if ku == 0 {
|
if ku == 0 {
|
||||||
return nil, errors.New("at least one key usage must be set")
|
return nil, errors.New("at least one key usage must be set")
|
||||||
}
|
}
|
||||||
|
|
@ -296,14 +276,6 @@ func makeTemplate(randReader io.Reader, profile *certProfile, pubKey []byte, tbc
|
||||||
// BR 7.1.2.1.2 Root CA Extensions
|
// BR 7.1.2.1.2 Root CA Extensions
|
||||||
// Extension Presence Critical Description
|
// Extension Presence Critical Description
|
||||||
// extKeyUsage MUST NOT N -
|
// extKeyUsage MUST NOT N -
|
||||||
case ocspCert:
|
|
||||||
cert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageOCSPSigning}
|
|
||||||
// ASN.1 NULL is 0x05, 0x00
|
|
||||||
ocspNoCheckExt := pkix.Extension{Id: oidOCSPNoCheck, Value: []byte{5, 0}}
|
|
||||||
cert.ExtraExtensions = append(cert.ExtraExtensions, ocspNoCheckExt)
|
|
||||||
cert.IsCA = false
|
|
||||||
case crlCert:
|
|
||||||
cert.IsCA = false
|
|
||||||
case requestCert, intermediateCert:
|
case requestCert, intermediateCert:
|
||||||
// id-kp-serverAuth is included in intermediate certificates, as required by
|
// id-kp-serverAuth is included in intermediate certificates, as required by
|
||||||
// Section 7.1.2.10.6 of the CA/BF Baseline Requirements.
|
// Section 7.1.2.10.6 of the CA/BF Baseline Requirements.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
|
@ -174,73 +173,6 @@ func TestMakeTemplateRestrictedCrossCertificate(t *testing.T) {
|
||||||
test.AssertEquals(t, cert.ExtKeyUsage[0], x509.ExtKeyUsageServerAuth)
|
test.AssertEquals(t, cert.ExtKeyUsage[0], x509.ExtKeyUsageServerAuth)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMakeTemplateOCSP(t *testing.T) {
|
|
||||||
s, ctx := pkcs11helpers.NewSessionWithMock()
|
|
||||||
ctx.GenerateRandomFunc = realRand
|
|
||||||
randReader := newRandReader(s)
|
|
||||||
profile := &certProfile{
|
|
||||||
SignatureAlgorithm: "SHA256WithRSA",
|
|
||||||
CommonName: "common name",
|
|
||||||
Organization: "organization",
|
|
||||||
Country: "country",
|
|
||||||
OCSPURL: "ocsp",
|
|
||||||
CRLURL: "crl",
|
|
||||||
IssuerURL: "issuer",
|
|
||||||
NotAfter: "2018-05-18 11:31:00",
|
|
||||||
NotBefore: "2018-05-18 11:31:00",
|
|
||||||
}
|
|
||||||
pubKey := samplePubkey()
|
|
||||||
|
|
||||||
cert, err := makeTemplate(randReader, profile, pubKey, nil, ocspCert)
|
|
||||||
test.AssertNotError(t, err, "makeTemplate failed")
|
|
||||||
|
|
||||||
test.Assert(t, !cert.IsCA, "IsCA is set")
|
|
||||||
// Check KU is only KeyUsageDigitalSignature
|
|
||||||
test.AssertEquals(t, cert.KeyUsage, x509.KeyUsageDigitalSignature)
|
|
||||||
// Check there is a single EKU with id-kp-OCSPSigning
|
|
||||||
test.AssertEquals(t, len(cert.ExtKeyUsage), 1)
|
|
||||||
test.AssertEquals(t, cert.ExtKeyUsage[0], x509.ExtKeyUsageOCSPSigning)
|
|
||||||
// Check ExtraExtensions contains a single id-pkix-ocsp-nocheck
|
|
||||||
hasExt := false
|
|
||||||
asnNULL := []byte{5, 0}
|
|
||||||
for _, ext := range cert.ExtraExtensions {
|
|
||||||
if ext.Id.Equal(oidOCSPNoCheck) {
|
|
||||||
if hasExt {
|
|
||||||
t.Error("template contains multiple id-pkix-ocsp-nocheck extensions")
|
|
||||||
}
|
|
||||||
hasExt = true
|
|
||||||
if !bytes.Equal(ext.Value, asnNULL) {
|
|
||||||
t.Errorf("id-pkix-ocsp-nocheck has unexpected content: want %x, got %x", asnNULL, ext.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
test.Assert(t, hasExt, "template doesn't contain id-pkix-ocsp-nocheck extensions")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMakeTemplateCRL(t *testing.T) {
|
|
||||||
s, ctx := pkcs11helpers.NewSessionWithMock()
|
|
||||||
ctx.GenerateRandomFunc = realRand
|
|
||||||
randReader := newRandReader(s)
|
|
||||||
profile := &certProfile{
|
|
||||||
SignatureAlgorithm: "SHA256WithRSA",
|
|
||||||
CommonName: "common name",
|
|
||||||
Organization: "organization",
|
|
||||||
Country: "country",
|
|
||||||
OCSPURL: "ocsp",
|
|
||||||
CRLURL: "crl",
|
|
||||||
IssuerURL: "issuer",
|
|
||||||
NotAfter: "2018-05-18 11:31:00",
|
|
||||||
NotBefore: "2018-05-18 11:31:00",
|
|
||||||
}
|
|
||||||
pubKey := samplePubkey()
|
|
||||||
|
|
||||||
cert, err := makeTemplate(randReader, profile, pubKey, nil, crlCert)
|
|
||||||
test.AssertNotError(t, err, "makeTemplate failed")
|
|
||||||
|
|
||||||
test.Assert(t, !cert.IsCA, "IsCA is set")
|
|
||||||
test.AssertEquals(t, cert.KeyUsage, x509.KeyUsageCRLSign)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyProfile(t *testing.T) {
|
func TestVerifyProfile(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
profile certProfile
|
profile certProfile
|
||||||
|
|
@ -366,114 +298,6 @@ func TestVerifyProfile(t *testing.T) {
|
||||||
},
|
},
|
||||||
certType: []certType{rootCert},
|
certType: []certType{rootCert},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
profile: certProfile{
|
|
||||||
NotBefore: "a",
|
|
||||||
NotAfter: "b",
|
|
||||||
SignatureAlgorithm: "c",
|
|
||||||
CommonName: "d",
|
|
||||||
Organization: "e",
|
|
||||||
Country: "f",
|
|
||||||
IssuerURL: "g",
|
|
||||||
KeyUsages: []string{"j"},
|
|
||||||
},
|
|
||||||
certType: []certType{ocspCert},
|
|
||||||
expectedErr: "key-usages cannot be set for a delegated signer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: certProfile{
|
|
||||||
NotBefore: "a",
|
|
||||||
NotAfter: "b",
|
|
||||||
SignatureAlgorithm: "c",
|
|
||||||
CommonName: "d",
|
|
||||||
Organization: "e",
|
|
||||||
Country: "f",
|
|
||||||
IssuerURL: "g",
|
|
||||||
CRLURL: "i",
|
|
||||||
},
|
|
||||||
certType: []certType{ocspCert},
|
|
||||||
expectedErr: "crl-url cannot be set for a delegated signer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: certProfile{
|
|
||||||
NotBefore: "a",
|
|
||||||
NotAfter: "b",
|
|
||||||
SignatureAlgorithm: "c",
|
|
||||||
CommonName: "d",
|
|
||||||
Organization: "e",
|
|
||||||
Country: "f",
|
|
||||||
IssuerURL: "g",
|
|
||||||
OCSPURL: "h",
|
|
||||||
},
|
|
||||||
certType: []certType{ocspCert},
|
|
||||||
expectedErr: "ocsp-url cannot be set for a delegated signer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: certProfile{
|
|
||||||
NotBefore: "a",
|
|
||||||
NotAfter: "b",
|
|
||||||
SignatureAlgorithm: "c",
|
|
||||||
CommonName: "d",
|
|
||||||
Organization: "e",
|
|
||||||
Country: "f",
|
|
||||||
IssuerURL: "g",
|
|
||||||
},
|
|
||||||
certType: []certType{ocspCert},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: certProfile{
|
|
||||||
NotBefore: "a",
|
|
||||||
NotAfter: "b",
|
|
||||||
SignatureAlgorithm: "c",
|
|
||||||
CommonName: "d",
|
|
||||||
Organization: "e",
|
|
||||||
Country: "f",
|
|
||||||
IssuerURL: "g",
|
|
||||||
KeyUsages: []string{"j"},
|
|
||||||
},
|
|
||||||
certType: []certType{crlCert},
|
|
||||||
expectedErr: "key-usages cannot be set for a delegated signer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: certProfile{
|
|
||||||
NotBefore: "a",
|
|
||||||
NotAfter: "b",
|
|
||||||
SignatureAlgorithm: "c",
|
|
||||||
CommonName: "d",
|
|
||||||
Organization: "e",
|
|
||||||
Country: "f",
|
|
||||||
IssuerURL: "g",
|
|
||||||
CRLURL: "i",
|
|
||||||
},
|
|
||||||
certType: []certType{crlCert},
|
|
||||||
expectedErr: "crl-url cannot be set for a delegated signer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: certProfile{
|
|
||||||
NotBefore: "a",
|
|
||||||
NotAfter: "b",
|
|
||||||
SignatureAlgorithm: "c",
|
|
||||||
CommonName: "d",
|
|
||||||
Organization: "e",
|
|
||||||
Country: "f",
|
|
||||||
IssuerURL: "g",
|
|
||||||
OCSPURL: "h",
|
|
||||||
},
|
|
||||||
certType: []certType{crlCert},
|
|
||||||
expectedErr: "ocsp-url cannot be set for a delegated signer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
profile: certProfile{
|
|
||||||
NotBefore: "a",
|
|
||||||
NotAfter: "b",
|
|
||||||
SignatureAlgorithm: "c",
|
|
||||||
CommonName: "d",
|
|
||||||
Organization: "e",
|
|
||||||
Country: "f",
|
|
||||||
IssuerURL: "g",
|
|
||||||
},
|
|
||||||
certType: []certType{crlCert},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
profile: certProfile{
|
profile: certProfile{
|
||||||
NotBefore: "a",
|
NotBefore: "a",
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/letsencrypt/boulder/pkcs11helpers"
|
|
||||||
"github.com/miekg/pkcs11"
|
"github.com/miekg/pkcs11"
|
||||||
|
|
||||||
|
"github.com/letsencrypt/boulder/pkcs11helpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var stringToCurve = map[string]elliptic.Curve{
|
var stringToCurve = map[string]elliptic.Curve{
|
||||||
|
|
@ -70,7 +71,7 @@ func ecPub(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if pubKey.Curve != expectedCurve {
|
if pubKey.Curve != expectedCurve {
|
||||||
return nil, errors.New("Returned EC parameters doesn't match expected curve")
|
return nil, errors.New("returned EC parameters doesn't match expected curve")
|
||||||
}
|
}
|
||||||
log.Printf("\tX: %X\n", pubKey.X.Bytes())
|
log.Printf("\tX: %X\n", pubKey.X.Bytes())
|
||||||
log.Printf("\tY: %X\n", pubKey.Y.Bytes())
|
log.Printf("\tY: %X\n", pubKey.Y.Bytes())
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/letsencrypt/boulder/pkcs11helpers"
|
|
||||||
"github.com/miekg/pkcs11"
|
"github.com/miekg/pkcs11"
|
||||||
|
|
||||||
|
"github.com/letsencrypt/boulder/pkcs11helpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type hsmRandReader struct {
|
type hsmRandReader struct {
|
||||||
|
|
@ -49,7 +50,7 @@ func generateKey(session *pkcs11helpers.Session, label string, outputPath string
|
||||||
{Type: pkcs11.CKA_LABEL, Value: []byte(label)},
|
{Type: pkcs11.CKA_LABEL, Value: []byte(label)},
|
||||||
})
|
})
|
||||||
if err != pkcs11helpers.ErrNoObject {
|
if err != pkcs11helpers.ErrNoObject {
|
||||||
return nil, fmt.Errorf("expected no preexisting objects with label %q in slot for key storage. got error: %s", label, err)
|
return nil, fmt.Errorf("expected no preexisting objects with label %q in slot for key storage. got error: %w", label, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pubKey crypto.PublicKey
|
var pubKey crypto.PublicKey
|
||||||
|
|
@ -58,25 +59,25 @@ func generateKey(session *pkcs11helpers.Session, label string, outputPath string
|
||||||
case "rsa":
|
case "rsa":
|
||||||
pubKey, keyID, err = rsaGenerate(session, label, config.RSAModLength)
|
pubKey, keyID, err = rsaGenerate(session, label, config.RSAModLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate RSA key pair: %s", err)
|
return nil, fmt.Errorf("failed to generate RSA key pair: %w", err)
|
||||||
}
|
}
|
||||||
case "ecdsa":
|
case "ecdsa":
|
||||||
pubKey, keyID, err = ecGenerate(session, label, config.ECDSACurve)
|
pubKey, keyID, err = ecGenerate(session, label, config.ECDSACurve)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate ECDSA key pair: %s", err)
|
return nil, fmt.Errorf("failed to generate ECDSA key pair: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
der, err := x509.MarshalPKIXPublicKey(pubKey)
|
der, err := x509.MarshalPKIXPublicKey(pubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to marshal public key: %s", err)
|
return nil, fmt.Errorf("failed to marshal public key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pemBytes := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: der})
|
pemBytes := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: der})
|
||||||
log.Printf("Public key PEM:\n%s\n", pemBytes)
|
log.Printf("Public key PEM:\n%s\n", pemBytes)
|
||||||
err = writeFile(outputPath, pemBytes)
|
err = writeFile(outputPath, pemBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to write public key to %q: %s", outputPath, err)
|
return nil, fmt.Errorf("failed to write public key to %q: %w", outputPath, err)
|
||||||
}
|
}
|
||||||
log.Printf("Public key written to %q\n", outputPath)
|
log.Printf("Public key written to %q\n", outputPath)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ type intermediateConfig struct {
|
||||||
SkipLints []string `yaml:"skip-lints"`
|
SkipLints []string `yaml:"skip-lints"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic intermediateConfig) validate(ct certType) error {
|
func (ic intermediateConfig) validate() error {
|
||||||
err := ic.PKCS11.validate()
|
err := ic.PKCS11.validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -260,7 +260,7 @@ func (ic intermediateConfig) validate(ct certType) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certificate profile
|
// Certificate profile
|
||||||
err = ic.CertProfile.verifyProfile(ct)
|
err = ic.CertProfile.verifyProfile(intermediateCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -504,7 +504,7 @@ func loadCert(filename string) (*x509.Certificate, error) {
|
||||||
log.Printf("Loaded certificate from %s\n", filename)
|
log.Printf("Loaded certificate from %s\n", filename)
|
||||||
block, _ := pem.Decode(certPEM)
|
block, _ := pem.Decode(certPEM)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return nil, fmt.Errorf("No data in cert PEM file %s", filename)
|
return nil, fmt.Errorf("no data in cert PEM file %q", filename)
|
||||||
}
|
}
|
||||||
cert, err := x509.ParseCertificate(block.Bytes)
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -599,7 +599,7 @@ func loadPubKey(filename string) (crypto.PublicKey, []byte, error) {
|
||||||
log.Printf("Loaded public key from %s\n", filename)
|
log.Printf("Loaded public key from %s\n", filename)
|
||||||
block, _ := pem.Decode(keyPEM)
|
block, _ := pem.Decode(keyPEM)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return nil, nil, fmt.Errorf("No data in cert PEM file %s", filename)
|
return nil, nil, fmt.Errorf("no data in cert PEM file %q", filename)
|
||||||
}
|
}
|
||||||
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -658,17 +658,14 @@ func rootCeremony(configBytes []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func intermediateCeremony(configBytes []byte, ct certType) error {
|
func intermediateCeremony(configBytes []byte) error {
|
||||||
if ct != intermediateCert && ct != ocspCert && ct != crlCert {
|
|
||||||
return fmt.Errorf("wrong certificate type provided")
|
|
||||||
}
|
|
||||||
var config intermediateConfig
|
var config intermediateConfig
|
||||||
err := strictyaml.Unmarshal(configBytes, &config)
|
err := strictyaml.Unmarshal(configBytes, &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse config: %s", err)
|
return fmt.Errorf("failed to parse config: %s", err)
|
||||||
}
|
}
|
||||||
log.Printf("Preparing intermediate ceremony for %s\n", config.Outputs.CertificatePath)
|
log.Printf("Preparing intermediate ceremony for %s\n", config.Outputs.CertificatePath)
|
||||||
err = config.validate(ct)
|
err = config.validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to validate config: %s", err)
|
return fmt.Errorf("failed to validate config: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -684,7 +681,7 @@ func intermediateCeremony(configBytes []byte, ct certType) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
template, err := makeTemplate(randReader, &config.CertProfile, pubBytes, nil, ct)
|
template, err := makeTemplate(randReader, &config.CertProfile, pubBytes, nil, intermediateCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create certificate profile: %s", err)
|
return fmt.Errorf("failed to create certificate profile: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -713,10 +710,7 @@ func intermediateCeremony(configBytes []byte, ct certType) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func crossCertCeremony(configBytes []byte, ct certType) error {
|
func crossCertCeremony(configBytes []byte) error {
|
||||||
if ct != crossCert {
|
|
||||||
return fmt.Errorf("wrong certificate type provided")
|
|
||||||
}
|
|
||||||
var config crossCertConfig
|
var config crossCertConfig
|
||||||
err := strictyaml.Unmarshal(configBytes, &config)
|
err := strictyaml.Unmarshal(configBytes, &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -743,7 +737,7 @@ func crossCertCeremony(configBytes []byte, ct certType) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
template, err := makeTemplate(randReader, &config.CertProfile, pubBytes, toBeCrossSigned, ct)
|
template, err := makeTemplate(randReader, &config.CertProfile, pubBytes, toBeCrossSigned, crossCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create certificate profile: %s", err)
|
return fmt.Errorf("failed to create certificate profile: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1044,12 +1038,12 @@ func main() {
|
||||||
log.Fatalf("root ceremony failed: %s", err)
|
log.Fatalf("root ceremony failed: %s", err)
|
||||||
}
|
}
|
||||||
case "cross-certificate":
|
case "cross-certificate":
|
||||||
err = crossCertCeremony(configBytes, crossCert)
|
err = crossCertCeremony(configBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("cross-certificate ceremony failed: %s", err)
|
log.Fatalf("cross-certificate ceremony failed: %s", err)
|
||||||
}
|
}
|
||||||
case "intermediate":
|
case "intermediate":
|
||||||
err = intermediateCeremony(configBytes, intermediateCert)
|
err = intermediateCeremony(configBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("intermediate ceremony failed: %s", err)
|
log.Fatalf("intermediate ceremony failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1058,11 +1052,6 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("cross-csr ceremony failed: %s", err)
|
log.Fatalf("cross-csr ceremony failed: %s", err)
|
||||||
}
|
}
|
||||||
case "ocsp-signer":
|
|
||||||
err = intermediateCeremony(configBytes, ocspCert)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("ocsp signer ceremony failed: %s", err)
|
|
||||||
}
|
|
||||||
case "key":
|
case "key":
|
||||||
err = keyCeremony(configBytes)
|
err = keyCeremony(configBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1078,12 +1067,7 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("crl ceremony failed: %s", err)
|
log.Fatalf("crl ceremony failed: %s", err)
|
||||||
}
|
}
|
||||||
case "crl-signer":
|
|
||||||
err = intermediateCeremony(configBytes, crlCert)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("crl signer ceremony failed: %s", err)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
log.Fatalf("unknown ceremony-type, must be one of: root, cross-certificate, intermediate, cross-csr, ocsp-signer, key, ocsp-response, crl, crl-signer")
|
log.Fatalf("unknown ceremony-type, must be one of: root, cross-certificate, intermediate, cross-csr, key, ocsp-response, crl")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -484,7 +484,7 @@ func TestIntermediateConfigValidate(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
err := tc.config.validate(intermediateCert)
|
err := tc.config.validate()
|
||||||
if err != nil && err.Error() != tc.expectedError {
|
if err != nil && err.Error() != tc.expectedError {
|
||||||
t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
|
t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
|
||||||
} else if err == nil && tc.expectedError != "" {
|
} else if err == nil && tc.expectedError != "" {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue