diff --git a/ocsp.go b/ocsp.go index 02a5f53d..57135eed 100644 --- a/ocsp.go +++ b/ocsp.go @@ -19,6 +19,7 @@ import ( "context" "crypto/x509" "encoding/pem" + "errors" "fmt" "io" "log" @@ -28,6 +29,10 @@ import ( "golang.org/x/crypto/ocsp" ) +// ErrNoOCSPServerSpecified indicates that OCSP information could not be +// stapled because the certificate does not support OCSP. +var ErrNoOCSPServerSpecified = errors.New("no OCSP server specified in certificate") + // stapleOCSP staples OCSP information to cert for hostname name. // If you have it handy, you should pass in the PEM-encoded certificate // bundle; otherwise the DER-encoded cert will have to be PEM-encoded. @@ -93,7 +98,7 @@ func stapleOCSP(ctx context.Context, ocspConfig OCSPConfig, storage Storage, cer // not contain a link to an OCSP server. But we should log it anyway. // There's nothing else we can do to get OCSP for this certificate, // so we can return here with the error. - return fmt.Errorf("no OCSP stapling for %v: %v", cert.Names, ocspErr) + return fmt.Errorf("no OCSP stapling for %v: %w", cert.Names, ocspErr) } gotNewOCSP = true } @@ -149,7 +154,7 @@ func getOCSPForCert(ocspConfig OCSPConfig, bundle []byte) ([]byte, *ocsp.Respons // we have only one certificate so far, we need to get the issuer cert. issuedCert := certificates[0] if len(issuedCert.OCSPServer) == 0 { - return nil, nil, fmt.Errorf("no OCSP server specified in certificate") + return nil, nil, ErrNoOCSPServerSpecified } // apply override for responder URL diff --git a/ocsp_test.go b/ocsp_test.go new file mode 100644 index 00000000..f50a4fef --- /dev/null +++ b/ocsp_test.go @@ -0,0 +1,39 @@ +package certmagic + +import ( + "context" + "errors" + "testing" +) + +// certWithoutOCSPServer is a minimal self-signed certificate. +const certWithoutOCSPServer = `-----BEGIN CERTIFICATE----- +MIIBEDCBtqADAgECAgEBMAoGCCqGSM49BAMCMAAwIhgPMDAwMTAxMDEwMDAwMDBa +GA8wMDAxMDEwMTAwMDAwMFowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ0p +7FKiv9p5rMMzntQeEBesKQnFR4XYFZ/SVlgJHFzd/QZ2sSxW+Mlbz78TTp4DMMIZ +J0z/Tw2+6fWdvoCYCW2jHTAbMBkGA1UdEQEB/wQPMA2CC2V4YW1wbGUuY29tMAoG +CCqGSM49BAMCA0kAMEYCIQDMbDvbJ/SXgRoblhBmt80F5iAyuOA0v20x0gpImK01 +oQIhANxdGJPvBaz0wOVBCSpd5jHbPxPxwqKZYJEes6y7eM+I +-----END CERTIFICATE-----` + +const privateKey = `-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIDJ59ptjq3MzILH4zn5IKoH1sYn+zrUeq2kD8+DD2x+OoAoGCCqGSM49 +AwEHoUQDQgAEnSnsUqK/2nmswzOe1B4QF6wpCcVHhdgVn9JWWAkcXN39BnaxLFb4 +yVvPvxNOngMwwhknTP9PDb7p9Z2+gJgJbQ== +-----END EC PRIVATE KEY-----` + +func TestOCSPServerNotSpecified(t *testing.T) { + var config OCSPConfig + storage := &FileStorage{Path: t.TempDir()} + + pemCert := []byte(certWithoutOCSPServer) + cert, err := makeCertificate(pemCert, []byte(privateKey)) + if err != nil { + t.Fatal("couldn't make certificate:", err) + } + + err = stapleOCSP(context.Background(), config, storage, &cert, pemCert) + if !errors.Is(err, ErrNoOCSPServerSpecified) { + t.Error("expected ErrOCSPServerNotSpecified in error", err) + } +}