diff --git a/cmd/ceremony/README.md b/cmd/ceremony/README.md index 80cadeb6c..dab07ed7e 100644 --- a/cmd/ceremony/README.md +++ b/cmd/ceremony/README.md @@ -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. | diff --git a/cmd/ceremony/cert.go b/cmd/ceremony/cert.go index 397c3b732..b8a2ecba3 100644 --- a/cmd/ceremony/cert.go +++ b/cmd/ceremony/cert.go @@ -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. diff --git a/cmd/ceremony/cert_test.go b/cmd/ceremony/cert_test.go index 0549b9a92..d471a63c6 100644 --- a/cmd/ceremony/cert_test.go +++ b/cmd/ceremony/cert_test.go @@ -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", diff --git a/cmd/ceremony/ecdsa.go b/cmd/ceremony/ecdsa.go index 65f5c6f99..3adec7313 100644 --- a/cmd/ceremony/ecdsa.go +++ b/cmd/ceremony/ecdsa.go @@ -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()) diff --git a/cmd/ceremony/key.go b/cmd/ceremony/key.go index e0ed20594..2315a2081 100644 --- a/cmd/ceremony/key.go +++ b/cmd/ceremony/key.go @@ -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) diff --git a/cmd/ceremony/main.go b/cmd/ceremony/main.go index 12cc9249c..e5537926a 100644 --- a/cmd/ceremony/main.go +++ b/cmd/ceremony/main.go @@ -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") } } diff --git a/cmd/ceremony/main_test.go b/cmd/ceremony/main_test.go index 44dae91e7..1b318e58e 100644 --- a/cmd/ceremony/main_test.go +++ b/cmd/ceremony/main_test.go @@ -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 != "" {