Skip to content

Commit f4f31d0

Browse files
committed
Added Unit test and incorporated review comments
Signed-off-by: Mukuls77 <[email protected]>
1 parent 5860b37 commit f4f31d0

File tree

2 files changed

+40
-85
lines changed

2 files changed

+40
-85
lines changed

pkg/cosign/verify.go

Lines changed: 9 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -216,86 +216,15 @@ func verifyOCISignature(ctx context.Context, verifier signature.Verifier, sig pa
216216
return verifier.VerifySignature(bytes.NewReader(signature), bytes.NewReader(payload), options.WithContext(ctx))
217217
}
218218

219-
// ValidateAndUnpackCert creates a Verifier from a certificate. Veries that the certificate
220-
// chains up to a trusted root. Optionally verifies the subject and issuer of the certificate.
219+
// ValidateAndUnpackCert calls ValidateAndUnpackCertWithIntermediates() by passing intermediate
220+
// certs from checkOpts as seperate argument
221221
func ValidateAndUnpackCert(cert *x509.Certificate, co *CheckOpts) (signature.Verifier, error) {
222-
verifier, err := signature.LoadVerifier(cert.PublicKey, crypto.SHA256)
223-
if err != nil {
224-
return nil, fmt.Errorf("invalid certificate found on signature: %w", err)
225-
}
226-
227-
// Handle certificates where the Subject Alternative Name is not set to a supported
228-
// GeneralName (RFC 5280 4.2.1.6). Go only supports DNS, IP addresses, email addresses,
229-
// or URIs as SANs. Fulcio can issue a certificate with an OtherName GeneralName, so
230-
// remove the unhandled critical SAN extension before verifying.
231-
if len(cert.UnhandledCriticalExtensions) > 0 {
232-
var unhandledExts []asn1.ObjectIdentifier
233-
for _, oid := range cert.UnhandledCriticalExtensions {
234-
if !oid.Equal(cryptoutils.SANOID) {
235-
unhandledExts = append(unhandledExts, oid)
236-
}
237-
}
238-
cert.UnhandledCriticalExtensions = unhandledExts
239-
}
240-
241-
// Now verify the cert, then the signature.
242-
chains, err := TrustedCert(cert, co.RootCerts, co.IntermediateCerts)
243-
if err != nil {
244-
return nil, err
245-
}
246-
247-
err = CheckCertificatePolicy(cert, co)
248-
if err != nil {
249-
return nil, err
250-
}
251-
252-
// If IgnoreSCT is set, skip the SCT check
253-
if co.IgnoreSCT {
254-
return verifier, nil
255-
}
256-
contains, err := ContainsSCT(cert.Raw)
257-
if err != nil {
258-
return nil, err
259-
}
260-
if !contains && len(co.SCT) == 0 {
261-
return nil, &VerificationFailure{
262-
fmt.Errorf("certificate does not include required embedded SCT and no detached SCT was set"),
263-
}
264-
}
265-
// handle if chains has more than one chain - grab first and print message
266-
if len(chains) > 1 {
267-
fmt.Fprintf(os.Stderr, "**Info** Multiple valid certificate chains found. Selecting the first to verify the SCT.\n")
268-
}
269-
if contains {
270-
if err := VerifyEmbeddedSCT(context.Background(), chains[0], co.CTLogPubKeys); err != nil {
271-
return nil, err
272-
}
273-
} else {
274-
chain := chains[0]
275-
if len(chain) < 2 {
276-
return nil, errors.New("certificate chain must contain at least a certificate and its issuer")
277-
}
278-
certPEM, err := cryptoutils.MarshalCertificateToPEM(chain[0])
279-
if err != nil {
280-
return nil, err
281-
}
282-
chainPEM, err := cryptoutils.MarshalCertificatesToPEM(chain[1:])
283-
if err != nil {
284-
return nil, err
285-
}
286-
if err := VerifySCT(context.Background(), certPEM, chainPEM, co.SCT, co.CTLogPubKeys); err != nil {
287-
return nil, err
288-
}
289-
}
290-
291-
return verifier, nil
222+
return ValidateAndUnpackCertWithIntermediates(cert, co, co.IntermediateCerts)
292223
}
293224

294-
// ValidateAndUnpackCertWithIntermediates function has same logic as ValidateAndUnpackCert.
295-
// Main diffrence is that we can not use ValidateAndUnpackCert in multi thread invocation
296-
// as it uses a common reference of CheckOpts so in multi thread invocation co.intermediateCert object
297-
// can get overwritten my multiple threads. So to solve this ValidateAndUnpackCertWithIntermediates
298-
// is created which has a separate argument for Intermediate certs.
225+
// ValidateAndUnpackCertWithIntermediates creates a Verifier from a certificate. Verifies that the
226+
// certificate chains up to a trusted root using intermediate cert passed as seperate argument.
227+
// Optionally verifies the subject and issuer of the certificate.
299228
func ValidateAndUnpackCertWithIntermediates(cert *x509.Certificate, co *CheckOpts, intermediateCerts *x509.CertPool) (signature.Verifier, error) {
300229
verifier, err := signature.LoadVerifier(cert.PublicKey, crypto.SHA256)
301230
if err != nil {
@@ -317,9 +246,6 @@ func ValidateAndUnpackCertWithIntermediates(cert *x509.Certificate, co *CheckOpt
317246
}
318247

319248
// Now verify the cert, then the signature.
320-
if intermediateCerts == nil {
321-
intermediateCerts = co.IntermediateCerts
322-
}
323249
chains, err := TrustedCert(cert, co.RootCerts, intermediateCerts)
324250

325251
if err != nil {
@@ -803,11 +729,9 @@ func verifyInternal(ctx context.Context, sig oci.Signature, h v1.Hash,
803729
return false, err
804730
}
805731
// If there is no chain annotation present, we preserve the pools set in the CheckOpts.
806-
var pool = (*x509.CertPool)(nil)
807-
if len(chain) > 0 {
808-
if len(chain) == 1 {
809-
co.IntermediateCerts = nil
810-
} else if co.IntermediateCerts == nil {
732+
var pool *x509.CertPool
733+
if len(chain) > 1 {
734+
if co.IntermediateCerts == nil {
811735
// If the intermediate certs have not been loaded in by TUF
812736
pool = x509.NewCertPool()
813737
for _, cert := range chain[:len(chain)-1] {

pkg/cosign/verify_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,37 @@ func TestValidateAndUnpackCertWithIdentities(t *testing.T) {
12281228
}
12291229
}
12301230
}
1231+
1232+
func TestValidateAndUnpackCertWithIntermediatesSuccess(t *testing.T) {
1233+
subject := "email@email"
1234+
oidcIssuer := "https://accounts.google.com"
1235+
1236+
rootCert, rootKey, _ := test.GenerateRootCa()
1237+
subCert, subKey, _ := test.GenerateSubordinateCa(rootCert, rootKey)
1238+
leafCert, _, _ := test.GenerateLeafCert(subject, oidcIssuer, subCert, subKey)
1239+
1240+
rootPool := x509.NewCertPool()
1241+
rootPool.AddCert(rootCert)
1242+
subPool := x509.NewCertPool()
1243+
rootPool.AddCert(subCert)
1244+
subPool.AddCert(subCert)
1245+
1246+
co := &CheckOpts{
1247+
RootCerts: rootPool,
1248+
IgnoreSCT: true,
1249+
Identities: []Identity{{Subject: subject, Issuer: oidcIssuer}},
1250+
}
1251+
1252+
_, err := ValidateAndUnpackCertWithIntermediates(leafCert, co, subPool)
1253+
if err != nil {
1254+
t.Errorf("ValidateAndUnpackCertWithIntermediates expected no error, got err = %v", err)
1255+
}
1256+
err = CheckCertificatePolicy(leafCert, co)
1257+
if err != nil {
1258+
t.Errorf("CheckCertificatePolicy expected no error, got err = %v", err)
1259+
}
1260+
}
1261+
12311262
func TestCompareSigs(t *testing.T) {
12321263
// TODO(nsmith5): Add test cases for invalid signature, missing signature etc
12331264
tests := []struct {

0 commit comments

Comments
 (0)