diff --git a/cmd/notation/sign.go b/cmd/notation/sign.go index b6cf1261..6fb302a0 100644 --- a/cmd/notation/sign.go +++ b/cmd/notation/sign.go @@ -231,10 +231,10 @@ func prepareSigningOpts(ctx context.Context, opts *signOpts) (notation.SignOptio return notation.SignOptions{}, err } if len(rootCerts) == 0 { - return notation.SignOptions{}, fmt.Errorf("cannot find any certificate from %q. Expecting one x509 root CA certificate in PEM or DER format from the file", opts.tsaRootCertificatePath) + return notation.SignOptions{}, fmt.Errorf("cannot find any certificate from %q. Expecting one x509 root certificate in PEM or DER format from the file", opts.tsaRootCertificatePath) } if len(rootCerts) > 1 { - return notation.SignOptions{}, fmt.Errorf("find more than one certificates from %q. Expecting one x509 root CA certificate in PEM or DER format from the file", opts.tsaRootCertificatePath) + return notation.SignOptions{}, fmt.Errorf("find more than one certificates from %q. Expecting one x509 root certificate in PEM or DER format from the file", opts.tsaRootCertificatePath) } tsaRootCert := rootCerts[0] isRoot, err := nx509.IsRootCertificate(tsaRootCert) @@ -242,7 +242,7 @@ func prepareSigningOpts(ctx context.Context, opts *signOpts) (notation.SignOptio return notation.SignOptions{}, fmt.Errorf("failed to check root certificate with error: %w", err) } if !isRoot { - return notation.SignOptions{}, fmt.Errorf("cannot find root CA certificate from %q. Expecting one x509 root CA certificate in PEM or DER format from the file", opts.tsaRootCertificatePath) + return notation.SignOptions{}, fmt.Errorf("certificate from %q is not a root certificate. Expecting one x509 root certificate in PEM or DER format from the file", opts.tsaRootCertificatePath) } rootCAs := x509.NewCertPool() diff --git a/test/e2e/suite/command/sign.go b/test/e2e/suite/command/sign.go index c986fcbe..e147f1e0 100644 --- a/test/e2e/suite/command/sign.go +++ b/test/e2e/suite/command/sign.go @@ -280,21 +280,21 @@ var _ = Describe("notation sign", func() { }) }) - It("with empty tsa server", func() { + It("with timestamping and empty tsa server", func() { Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("sign", "--timestamp-url", "", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "globalsignTSARoot.cer"), artifact.ReferenceWithDigest()). MatchErrKeyWords("Error: timestamping: tsa url cannot be empty") }) }) - It("with empty tsa root cert", func() { + It("with timestamping and empty tsa root cert", func() { Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("sign", "--timestamp-url", "dummy", "--timestamp-root-cert", "", artifact.ReferenceWithDigest()). MatchErrKeyWords("Error: timestamping: tsa root certificate path cannot be empty") }) }) - It("with invalid tsa server", func() { + It("with timestamping and invalid tsa server", func() { Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("sign", "--timestamp-url", "http://invalid.com", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "globalsignTSARoot.cer"), artifact.ReferenceWithDigest()). MatchErrKeyWords("Error: timestamp: Post \"http://invalid.com\""). @@ -302,26 +302,34 @@ var _ = Describe("notation sign", func() { }) }) - It("with invalid tsa root certificate", func() { + It("with timestamping and invalid tsa root certificate", func() { Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("sign", "--timestamp-url", "http://timestamp.digicert.com", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "invalid.crt"), artifact.ReferenceWithDigest()). MatchErrKeyWords("Error: x509: malformed certificate") }) }) - It("with more than certificates in tsa root certificate file", func() { + It("with timestamping and more than one certificates in tsa root certificate file", func() { Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("sign", "--timestamp-url", "http://timestamp.digicert.com", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "CertChain.pem"), artifact.ReferenceWithDigest()). MatchErrKeyWords("find more than one certificates"). - MatchErrKeyWords("Expecting one x509 root CA certificate in PEM or DER format from the file") + MatchErrKeyWords("Expecting one x509 root certificate in PEM or DER format from the file") }) }) - It("with empty tsa root certificate file", func() { + It("with timestamping and empty tsa root certificate file", func() { Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("sign", "--timestamp-url", "http://timestamp.digicert.com", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "Empty.txt"), artifact.ReferenceWithDigest()). MatchErrKeyWords("cannot find any certificate from"). - MatchErrKeyWords("Expecting one x509 root CA certificate in PEM or DER format from the file") + MatchErrKeyWords("Expecting one x509 root certificate in PEM or DER format from the file") + }) + }) + + It("with timestamping and intermediate certificate file", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure().Exec("sign", "--timestamp-url", "http://timestamp.digicert.com", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "intermediate.pem"), artifact.ReferenceWithDigest()). + MatchErrKeyWords("is not a root certificate"). + MatchErrKeyWords("Expecting one x509 root certificate in PEM or DER format from the file") }) }) }) diff --git a/test/e2e/testdata/config/timestamp/intermediate.pem b/test/e2e/testdata/config/timestamp/intermediate.pem new file mode 100644 index 00000000..83e1ccec --- /dev/null +++ b/test/e2e/testdata/config/timestamp/intermediate.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICyjCCAbKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290 +MCAXDTIyMDYzMDE5MjAwM1oYDzMwMjExMDMxMTkyMDAzWjAYMRYwFAYDVQQDDA1J +bnRlcm1lZGlhdGUxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1JTs +aiC/7+bho43kMVyHDwCsuocYp4PvYahB59NsKDR4QbrImU5ziaQ94D0DQqthe9pm +qOW0SxN/vSRJAZFELxacrB9hc1y4MjiDYaRSt/LVx7astylBV/QRpmxWSEqp0Avu +6nMJivIa1sD0WIEchizx6jG9BI5ULr9LbJICYvMgDalQR+0JGG+rKWnf1mPZyxEu +9zEh215LCg5K56P3W5kC8fKBXSdSgTqZAvHzp6u78qet9S8gARtOEfS03A/7y7MC +U0Sn2wdQyQdci0PBsR2sTZvUw179Cr93r5aRbb3I6jXgMWHAP2vvIndb9CM9ePyY +yEy4Je7oWVVfMQ3CWQIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud +DwEB/wQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEALR0apUQVbWGmagLUz4Y/bRsl +mY9EJJXCiLuSxVWd3offjZfQTlGkQkCAW9FOQnm7JhEtaaHF1+AEVLo56/Gsd/hk +sXsrBagYGi72jun7QTb6j7iZ3X9zanrP3SjdkpjVnqxRfH83diSh0r68Xruq1NSK +qhUy1V+KQaXF0SSEutPqdTCoXUyxyXohVLU78uqZX/jx9Nc1XDuW9AZd+hMsLdk8 +qGJqHYFvj2vOHGMTeYk8dWgMBthQeL0wdsg2AvKtAvn6FQXCN7mKCWjpFTtYsU8v +NsesS9M/i+geJjR/8/DDT3RP7S100BtCMm4XfHfmKcjXVaBh5evQVqGsa6TKLw== +-----END CERTIFICATE----- \ No newline at end of file