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:
Aaron Gable 2025-07-17 16:28:26 -07:00 committed by GitHub
parent b9dbcdbba2
commit d5bb88b975
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 142 additions and 357 deletions

View File

@ -1,21 +1,20 @@
# `ceremony`
```
```sh
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` 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
* `cross-csr` - creates a CSR for signing by a third party, outputting a PEM CSR.
* `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.
* `ocsp-signer` - creates a delegated OCSP signing certificate and signs it using a signing key already on a HSM, outputting a PEM certificate
* `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
* `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
- `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
- `cross-csr`: creates a CSR for signing by a third party, outputting a PEM CSR.
- `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.
- `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
- `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.
@ -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`.
- `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. |
| `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. |
- `key`: object containing key generation related fields.
| 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`. |
| `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.
| Field | Description |
| --- | --- |
| `public-key-path` | Path to store generated PEM public key. |
| `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:
@ -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`.
### 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.
| 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. |
| `public-key-path` | Path to PEM subject public key for 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).
Example:
@ -106,8 +117,8 @@ pkcs11:
signing-key-slot: 0
signing-key-label: root signing key
inputs:
public-key-path: /home/user/intermediate-signing-pub.pem
issuer-certificate-path: /home/user/root-cert.pem
public-key-path: /home/user/intermediate-signing-pub.pem
outputs:
certificate-path: /home/user/intermediate-cert.pem
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`.
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.
| 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 |
| --- | --- |
| `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 |
| --- | --- |
| `public-key-path` | Path to PEM subject public key for certificate. |
- `outputs`: object containing paths to write outputs.
| Field | Description |
| --- | --- |
| `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`.
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`.
### 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
- `ceremony-type`: string describing the ceremony type, `key`.
- `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. |
| `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. |
- `key`: object containing key generation related fields.
| 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`. |
| `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.
| Field | Description |
| --- | --- |
| `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`.
- `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 |
| --- | --- |
| `certificate-path` | Path to PEM certificate to create a response for. |
| `issuer-certificate-path` | Path to PEM issuer certificate. |
| `delegated-issuer-certificate-path` | Path to PEM delegated issuer certificate, if one is being used. |
- `outputs`: object containing paths to write outputs.
| Field | Description |
| --- | --- |
| `response-path` | Path to store signed base64 encoded response. |
- `ocsp-profile`: object containing profile for the OCSP response.
| 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. |
@ -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`.
- `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 |
| --- | --- |
| `issuer-certificate-path` | Path to PEM issuer certificate. |
- `outputs`: object containing paths to write outputs.
| Field | Description |
| --- | --- |
| `crl-path` | Path to store signed PEM CRL. |
- `crl-profile`: object containing profile for the CRL.
| 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. |

View File

@ -76,8 +76,6 @@ type certType int
const (
rootCert certType = iota
intermediateCert
ocspCert
crlCert
crossCert
requestCert
)
@ -153,23 +151,12 @@ func (profile *certProfile) verifyProfile(ct certType) error {
}
// 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" {
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
}
@ -194,8 +181,6 @@ var stringToKeyUsage = map[string]x509.KeyUsage{
"Cert Sign": x509.KeyUsageCertSign,
}
var oidOCSPNoCheck = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 5}
func generateSKID(pk []byte) ([]byte, error) {
var pkixPublicKey struct {
Algo pkix.AlgorithmIdentifier
@ -252,11 +237,6 @@ func makeTemplate(randReader io.Reader, profile *certProfile, pubKey []byte, tbc
}
ku |= kuBit
}
if ct == ocspCert {
ku = x509.KeyUsageDigitalSignature
} else if ct == crlCert {
ku = x509.KeyUsageCRLSign
}
if ku == 0 {
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
// Extension Presence Critical Description
// 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:
// id-kp-serverAuth is included in intermediate certificates, as required by
// Section 7.1.2.10.6 of the CA/BF Baseline Requirements.

View File

@ -1,7 +1,6 @@
package main
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
@ -174,73 +173,6 @@ func TestMakeTemplateRestrictedCrossCertificate(t *testing.T) {
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) {
for _, tc := range []struct {
profile certProfile
@ -366,114 +298,6 @@ func TestVerifyProfile(t *testing.T) {
},
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{
NotBefore: "a",

View File

@ -7,8 +7,9 @@ import (
"fmt"
"log"
"github.com/letsencrypt/boulder/pkcs11helpers"
"github.com/miekg/pkcs11"
"github.com/letsencrypt/boulder/pkcs11helpers"
)
var stringToCurve = map[string]elliptic.Curve{
@ -70,7 +71,7 @@ func ecPub(
return nil, err
}
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("\tY: %X\n", pubKey.Y.Bytes())

View File

@ -7,8 +7,9 @@ import (
"fmt"
"log"
"github.com/letsencrypt/boulder/pkcs11helpers"
"github.com/miekg/pkcs11"
"github.com/letsencrypt/boulder/pkcs11helpers"
)
type hsmRandReader struct {
@ -49,7 +50,7 @@ func generateKey(session *pkcs11helpers.Session, label string, outputPath string
{Type: pkcs11.CKA_LABEL, Value: []byte(label)},
})
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
@ -58,25 +59,25 @@ func generateKey(session *pkcs11helpers.Session, label string, outputPath string
case "rsa":
pubKey, keyID, err = rsaGenerate(session, label, config.RSAModLength)
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":
pubKey, keyID, err = ecGenerate(session, label, config.ECDSACurve)
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)
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})
log.Printf("Public key PEM:\n%s\n", pemBytes)
err = writeFile(outputPath, pemBytes)
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)

View File

@ -239,7 +239,7 @@ type intermediateConfig struct {
SkipLints []string `yaml:"skip-lints"`
}
func (ic intermediateConfig) validate(ct certType) error {
func (ic intermediateConfig) validate() error {
err := ic.PKCS11.validate()
if err != nil {
return err
@ -260,7 +260,7 @@ func (ic intermediateConfig) validate(ct certType) error {
}
// Certificate profile
err = ic.CertProfile.verifyProfile(ct)
err = ic.CertProfile.verifyProfile(intermediateCert)
if err != nil {
return err
}
@ -504,7 +504,7 @@ func loadCert(filename string) (*x509.Certificate, error) {
log.Printf("Loaded certificate from %s\n", filename)
block, _ := pem.Decode(certPEM)
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)
if err != nil {
@ -599,7 +599,7 @@ func loadPubKey(filename string) (crypto.PublicKey, []byte, error) {
log.Printf("Loaded public key from %s\n", filename)
block, _ := pem.Decode(keyPEM)
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)
if err != nil {
@ -658,17 +658,14 @@ func rootCeremony(configBytes []byte) error {
return nil
}
func intermediateCeremony(configBytes []byte, ct certType) error {
if ct != intermediateCert && ct != ocspCert && ct != crlCert {
return fmt.Errorf("wrong certificate type provided")
}
func intermediateCeremony(configBytes []byte) error {
var config intermediateConfig
err := strictyaml.Unmarshal(configBytes, &config)
if err != nil {
return fmt.Errorf("failed to parse config: %s", err)
}
log.Printf("Preparing intermediate ceremony for %s\n", config.Outputs.CertificatePath)
err = config.validate(ct)
err = config.validate()
if err != nil {
return fmt.Errorf("failed to validate config: %s", err)
}
@ -684,7 +681,7 @@ func intermediateCeremony(configBytes []byte, ct certType) error {
if err != nil {
return err
}
template, err := makeTemplate(randReader, &config.CertProfile, pubBytes, nil, ct)
template, err := makeTemplate(randReader, &config.CertProfile, pubBytes, nil, intermediateCert)
if err != nil {
return fmt.Errorf("failed to create certificate profile: %s", err)
}
@ -713,10 +710,7 @@ func intermediateCeremony(configBytes []byte, ct certType) error {
return nil
}
func crossCertCeremony(configBytes []byte, ct certType) error {
if ct != crossCert {
return fmt.Errorf("wrong certificate type provided")
}
func crossCertCeremony(configBytes []byte) error {
var config crossCertConfig
err := strictyaml.Unmarshal(configBytes, &config)
if err != nil {
@ -743,7 +737,7 @@ func crossCertCeremony(configBytes []byte, ct certType) error {
if err != nil {
return err
}
template, err := makeTemplate(randReader, &config.CertProfile, pubBytes, toBeCrossSigned, ct)
template, err := makeTemplate(randReader, &config.CertProfile, pubBytes, toBeCrossSigned, crossCert)
if err != nil {
return fmt.Errorf("failed to create certificate profile: %s", err)
}
@ -1044,12 +1038,12 @@ func main() {
log.Fatalf("root ceremony failed: %s", err)
}
case "cross-certificate":
err = crossCertCeremony(configBytes, crossCert)
err = crossCertCeremony(configBytes)
if err != nil {
log.Fatalf("cross-certificate ceremony failed: %s", err)
}
case "intermediate":
err = intermediateCeremony(configBytes, intermediateCert)
err = intermediateCeremony(configBytes)
if err != nil {
log.Fatalf("intermediate ceremony failed: %s", err)
}
@ -1058,11 +1052,6 @@ func main() {
if err != nil {
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":
err = keyCeremony(configBytes)
if err != nil {
@ -1078,12 +1067,7 @@ func main() {
if err != nil {
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:
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")
}
}

View File

@ -484,7 +484,7 @@ func TestIntermediateConfigValidate(t *testing.T) {
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := tc.config.validate(intermediateCert)
err := tc.config.validate()
if err != nil && err.Error() != tc.expectedError {
t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
} else if err == nil && tc.expectedError != "" {