Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Timestamp #418

Merged
merged 105 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
4b42738
initial test
Two-Hearts Dec 1, 2023
ca5bba2
fix trust store
Two-Hearts Dec 4, 2023
73ec77c
resolved conflicts
Two-Hearts Dec 26, 2023
2937f68
Merge branch 'notaryproject:main' into tsa
Two-Hearts Dec 28, 2023
f06d289
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jan 12, 2024
9819ba2
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jan 15, 2024
8e6bbdb
initial commits
Two-Hearts Jan 15, 2024
b454646
initial commits
Two-Hearts Jan 15, 2024
d058046
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jan 16, 2024
1df563c
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jan 19, 2024
9cd5aaf
updated to use tspclient-go
Two-Hearts Jan 23, 2024
ef01821
resolved conflicts
Two-Hearts Jan 24, 2024
e655c04
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jan 31, 2024
ea97a99
updated tspclient-go
Two-Hearts Jan 31, 2024
fa4eaaf
test
Two-Hearts Feb 1, 2024
dc9c5fe
update
Two-Hearts Feb 1, 2024
00d7dfd
Merge branch 'notaryproject:main' into tsa
Two-Hearts Feb 1, 2024
62bacd0
resolved conflicts
Two-Hearts Feb 2, 2024
1f4bd5c
Merge branch 'notaryproject:main' into tsa
Two-Hearts Mar 18, 2024
3b98cd7
update sign with timestamping
Two-Hearts Mar 22, 2024
09810a9
resolved conflicts
Two-Hearts Mar 22, 2024
e598416
update timestamp verification
Two-Hearts Mar 22, 2024
be2ea0e
updated timestmap
Two-Hearts Mar 27, 2024
c8f8e4e
updated timestamp
Two-Hearts Mar 27, 2024
28e0166
resolve conflicts
Two-Hearts Mar 28, 2024
200a071
added tsa cert chain revocation check
Two-Hearts Apr 8, 2024
6ab5a0e
Merge branch 'notaryproject:main' into tsa
Two-Hearts Apr 8, 2024
53ee15c
update tsa
Two-Hearts Apr 8, 2024
e5aaefe
added tsa ocsp check
Two-Hearts Apr 8, 2024
2e674e4
updated timestamping
Two-Hearts Apr 8, 2024
31de40f
update
Two-Hearts Apr 10, 2024
f4536db
update
Two-Hearts Apr 11, 2024
998d79f
added skip tsa cert expire check
Two-Hearts Apr 11, 2024
545e1e7
update
Two-Hearts Apr 11, 2024
527b84a
added timestamp trust policy
Two-Hearts Apr 16, 2024
1e21a3d
update
Two-Hearts Apr 17, 2024
27a5b35
update
Two-Hearts Apr 17, 2024
90424bd
update
Two-Hearts Apr 17, 2024
d7a0396
timestamp trust policy
Two-Hearts Apr 17, 2024
12ac6b6
update
Two-Hearts Apr 18, 2024
6e36303
update
Two-Hearts Apr 18, 2024
bea674c
error msg
Two-Hearts Apr 18, 2024
f960e7b
resolve conflicts
Two-Hearts Apr 26, 2024
a510cbf
updated per spec
Two-Hearts May 8, 2024
3a8b24b
Merge branch 'notaryproject:main' into tsa
Two-Hearts May 8, 2024
de71d34
updated per spec
Two-Hearts May 8, 2024
cde5adb
updated tspclient-go
Two-Hearts May 10, 2024
9abd3c4
resolved conflicts
Two-Hearts Jun 4, 2024
d13d60c
updated timestamping
Two-Hearts Jun 4, 2024
c5ececc
updated timestamping
Two-Hearts Jun 4, 2024
d8f19cf
updated timestamping
Two-Hearts Jun 4, 2024
f1497b1
update
Two-Hearts Jun 11, 2024
6b29b3d
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jun 11, 2024
ee0b91b
build cert chain from tsa token
Two-Hearts Jun 11, 2024
3cdb0b2
update
Two-Hearts Jun 11, 2024
09075e7
update
Two-Hearts Jun 14, 2024
edeef34
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jun 18, 2024
b002bea
updated timestamping
Two-Hearts Jun 18, 2024
1a24903
first batch of tests
Two-Hearts Jun 18, 2024
d22e809
fixed tests
Two-Hearts Jun 18, 2024
a8811e5
added more tests
Two-Hearts Jun 19, 2024
6e558ee
update
Two-Hearts Jun 19, 2024
f642856
updated dependencies
Two-Hearts Jun 20, 2024
85fd953
fixed tests
Two-Hearts Jun 20, 2024
0697044
fixed tests
Two-Hearts Jun 20, 2024
a75b224
tsa root cert pool
Two-Hearts Jun 21, 2024
918f501
tsa root cert pool
Two-Hearts Jun 21, 2024
d8b3218
update timestamp
Two-Hearts Jun 21, 2024
b256493
update timestamp
Two-Hearts Jun 21, 2024
d06a838
added more tests
Two-Hearts Jun 24, 2024
d5f6868
updated tsa root cert pool
Two-Hearts Jun 24, 2024
329760b
updated tsa root cert pool
Two-Hearts Jun 24, 2024
48f2448
updated timestamp trust policy
Two-Hearts Jun 25, 2024
3a0de5f
update timestamp
Two-Hearts Jun 25, 2024
cfe3428
clean up
Two-Hearts Jun 25, 2024
573f592
clean up
Two-Hearts Jun 25, 2024
3ad1246
fixed tests
Two-Hearts Jun 25, 2024
ac78ce1
update timestamp
Two-Hearts Jun 25, 2024
925801f
updated log
Two-Hearts Jun 25, 2024
c1621e2
added exmaple tests for timestamp
Two-Hearts Jun 26, 2024
f987d28
test
Two-Hearts Jun 27, 2024
12b393e
clean up
Two-Hearts Jun 27, 2024
bf74212
resolved conflicts
Two-Hearts Jun 27, 2024
13006ce
fix tests
Two-Hearts Jun 27, 2024
938762e
updated timestamping
Two-Hearts Jul 1, 2024
d94d7b3
added more tests
Two-Hearts Jul 3, 2024
5aeef68
fixed build
Two-Hearts Jul 3, 2024
eb3eb88
updated per code review
Two-Hearts Jul 8, 2024
78999aa
updated per code review
Two-Hearts Jul 8, 2024
23a2280
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jul 9, 2024
1235960
update
Two-Hearts Jul 9, 2024
830b2bd
updated to tspclient-go v0.1.0
Two-Hearts Jul 10, 2024
d8498e5
updated per code review
Two-Hearts Jul 11, 2024
a601fce
update
Two-Hearts Jul 11, 2024
9f45e97
update
Two-Hearts Jul 11, 2024
45f3495
update
Two-Hearts Jul 11, 2024
de827c1
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jul 12, 2024
5c1a4b7
updated per code review
Two-Hearts Jul 12, 2024
bf97c57
updated per code review
Two-Hearts Jul 12, 2024
fe59bc2
Merge branch 'notaryproject:main' into tsa
Two-Hearts Jul 12, 2024
7d03fd2
updated per code review
Two-Hearts Jul 12, 2024
e0eb1b6
update
Two-Hearts Jul 12, 2024
c962941
update
Two-Hearts Jul 12, 2024
e50cf0a
updated log
Two-Hearts Jul 12, 2024
b94b3fd
updated per code review
Two-Hearts Jul 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions signer/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,12 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts
SigningTime: time.Now(),
SigningScheme: signature.SigningSchemeX509,
SigningAgent: signingAgentId,
Timestamper: opts.Timestamper,
TSARootCAs: opts.TSARootCAs,
}
if opts.Timestamper != nil && opts.TSARootCAs != nil {
signReq.Timestamper = opts.Timestamper
signReq.TSARootCAs = opts.TSARootCAs
} else if opts.Timestamper != nil || opts.TSARootCAs != nil {
return nil, nil, errors.New("timestamping: both Timestamper and TSARootCAs must be provided")
}

// Add expiry only if ExpiryDuration is not zero
Expand Down
30 changes: 30 additions & 0 deletions signer/signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,36 @@ func TestSignWithTimestamping(t *testing.T) {
})
}
}

// timestamping without timestamper
envelopeType := signature.RegisteredEnvelopeTypes()[0]
keyCert := keyCertPairCollections[0]
s, err := New(keyCert.key, keyCert.certs)
if err != nil {
t.Fatalf("NewSigner() error = %v", err)
}
ctx := context.Background()
desc, sOpts := generateSigningContent()
sOpts.SignatureMediaType = envelopeType
sOpts.TSARootCAs = x509.NewCertPool()
_, _, err = s.Sign(ctx, desc, sOpts)
expectedErrMsg := "timestamping: both Timestamper and TSARootCAs must be provided"
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected %s, but got %s", expectedErrMsg, err)
}

// timestamping without TSARootCAs
desc, sOpts = generateSigningContent()
sOpts.SignatureMediaType = envelopeType
sOpts.Timestamper, err = tspclient.NewHTTPTimestamper(nil, rfc3161URL)
if err != nil {
t.Fatal(err)
}
_, _, err = s.Sign(ctx, desc, sOpts)
expectedErrMsg = "timestamping: both Timestamper and TSARootCAs must be provided"
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected %s, but got %s", expectedErrMsg, err)
}
}

func TestSignBlobWithCertChain(t *testing.T) {
Expand Down
50 changes: 26 additions & 24 deletions verifier/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@
revocationTimestampClient := verifierOptions.RevocationTimestampClient
if revocationTimestampClient == nil {
var err error
revocationTimestampClient, err = revocation.NewTimestamp(&http.Client{Timeout: 5 * time.Second})
revocationTimestampClient, err = revocation.NewTimestamp(&http.Client{Timeout: 2 * time.Second})
if err != nil {
return nil, err

Check warning on line 137 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L137

Added line #L137 was not covered by tests
}
}

Expand Down Expand Up @@ -210,13 +210,13 @@
logger := log.GetLogger(ctx)
logger.Debugf("Verify signature of media type %v", opts.SignatureMediaType)
if v.blobTrustPolicyDoc == nil {
return nil, errors.New("blobTrustPolicyDoc is nil")

Check warning on line 213 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L213

Added line #L213 was not covered by tests
}

var trustPolicy *trustpolicy.BlobTrustPolicy
var err error
if opts.TrustPolicyName == "" {
trustPolicy, err = v.blobTrustPolicyDoc.GetGlobalTrustPolicy()

Check warning on line 219 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L219

Added line #L219 was not covered by tests
} else {
trustPolicy, err = v.blobTrustPolicyDoc.GetApplicableTrustPolicy(opts.TrustPolicyName)
}
Expand Down Expand Up @@ -298,7 +298,7 @@

logger.Debugf("Verify signature against artifact %v referenced as %s in signature media type %v", desc.Digest, artifactRef, envelopeMediaType)
if v.ociTrustPolicyDoc == nil {
return nil, errors.New("ociTrustPolicyDoc is nil")

Check warning on line 301 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L301

Added line #L301 was not covered by tests
}

trustPolicy, err := v.ociTrustPolicyDoc.GetApplicableTrustPolicy(artifactRef)
Expand Down Expand Up @@ -684,7 +684,7 @@
signerInfo := outcome.EnvelopeContent.SignerInfo
// under signing scheme notary.x509
if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 {
logger.Info("Under signing scheme notary.x509...")
logger.Debug("Under signing scheme notary.x509...")
return &notation.ValidationResult{
Error: verifyTimestamp(ctx, policyName, trustStores, signatureVerification, x509TrustStore, r, outcome),
Type: trustpolicy.TypeAuthenticTimestamp,
Expand All @@ -693,14 +693,14 @@
}

// under signing scheme notary.x509.signingAuthority
logger.Info("Under signing scheme notary.x509.signingAuthority...")
logger.Debug("Under signing scheme notary.x509.signingAuthority...")
authenticSigningTime := signerInfo.SignedAttributes.SigningTime
for _, cert := range signerInfo.CertificateChain {
if authenticSigningTime.Before(cert.NotBefore) || authenticSigningTime.After(cert.NotAfter) {
return &notation.ValidationResult{
Error: fmt.Errorf("certificate %q was not valid when the digital signature was produced at %q", cert.Subject, authenticSigningTime.Format(time.RFC1123Z)),
Type: trustpolicy.TypeAuthenticTimestamp,
Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp],

Check warning on line 703 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L700-L703

Added lines #L700 - L703 were not covered by tests
}
}
}
Expand Down Expand Up @@ -930,8 +930,8 @@
var expired bool
for _, cert := range signerInfo.CertificateChain {
if timeOfVerification.After(cert.NotAfter) {
expired = true
break

Check warning on line 934 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L933-L934

Added lines #L933 - L934 were not covered by tests
}
}
if !expired {
Expand All @@ -945,7 +945,7 @@
if !performTimestampVerification {
for _, cert := range signerInfo.CertificateChain {
if timeOfVerification.Before(cert.NotBefore) {
return fmt.Errorf("verification time is before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z))

Check warning on line 948 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L948

Added line #L948 was not covered by tests
}
if timeOfVerification.After(cert.NotAfter) {
return fmt.Errorf("verification time is after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z))
Expand All @@ -957,14 +957,16 @@
}

// Performing timestamp verification
logger.Info("Performing timestamp verification...")

// 1. Timestamp countersignature MUST be present
logger.Info("Checking timestamp countersignature existence...")
logger.Debug("Checking timestamp countersignature existence...")
if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 {
return errors.New("no timestamp countersignature was found in the signature envelope")
}

// 2. Verify the timestamp countersignature
logger.Info("Verifying the timestamp countersignature...")
logger.Debug("Verifying the timestamp countersignature...")
signedToken, err := tspclient.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature)
if err != nil {
return fmt.Errorf("failed to parse timestamp countersignature with error: %w", err)
Expand All @@ -973,6 +975,10 @@
if err != nil {
return fmt.Errorf("failed to get the timestamp TSTInfo with error: %w", err)
}
timestamp, err := info.Validate(signerInfo.Signature)
if err != nil {
return fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err)
}
trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, policyName, trustStores, x509TrustStore)
if err != nil {
return fmt.Errorf("failed to load tsa trust store with error: %w", err)
Expand All @@ -984,10 +990,6 @@
for _, trustedCerts := range trustTSACerts {
rootCertPool.AddCert(trustedCerts)
}
timestamp, err := info.Validate(signerInfo.Signature)
if err != nil {
return fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err)
}
tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{
CurrentTime: timestamp.Value,
Roots: rootCertPool,
Expand All @@ -997,41 +999,41 @@
}

// 3. Validate timestamping certificate chain
logger.Info("Validating timestamping certificate chain...")
logger.Debug("Validating timestamping certificate chain...")
if err := nx509.ValidateTimestampingCertChain(tsaCertChain); err != nil {
return fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err)

Check warning on line 1004 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L1004

Added line #L1004 was not covered by tests
}
logger.Info("TSA identity is: ", tsaCertChain[0].Subject)

// 4. Perform the timestamping certificate chain revocation check
logger.Info("Checking timestamping certificate chain revocation...")
// 4. Check the timestamp against the signing certificate chain
logger.Debug("Checking the timestamp against the signing certificate chain...")
logger.Debugf("Timestamp range: [%v, %v]", timestamp.Value.Add(-timestamp.Accuracy), timestamp.Value.Add(timestamp.Accuracy))
for _, cert := range signerInfo.CertificateChain {
if !timestamp.BoundedAfter(cert.NotBefore) {
return fmt.Errorf("timestamp can be before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z))
}
if !timestamp.BoundedBefore(cert.NotAfter) {
return fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z))
}
}

// 5. Perform the timestamping certificate chain revocation check
logger.Debug("Checking timestamping certificate chain revocation...")
certResults, err := r.Validate(tsaCertChain, time.Time{})
if err != nil {
return fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err)

Check warning on line 1024 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L1024

Added line #L1024 was not covered by tests
}
finalResult, problematicCertSubject := revocationFinalResult(certResults, tsaCertChain, logger)
switch finalResult {
case revocationresult.ResultOK:
logger.Debug("No verification impacting errors encountered while checking timestamping certificate chain revocation, status is OK")
case revocationresult.ResultRevoked:
return fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject)
default:

Check warning on line 1032 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L1030-L1032

Added lines #L1030 - L1032 were not covered by tests
// revocationresult.ResultUnknown
return fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject)

Check warning on line 1034 in verifier/verifier.go

View check run for this annotation

Codecov / codecov/patch

verifier/verifier.go#L1034

Added line #L1034 was not covered by tests
}

// 5. Check the timestamp against the signing certificate chain
logger.Info("Checking the timestamp against the signing certificate chain...")
logger.Infof("Timestamp range: [%v, %v]", timestamp.Value.Add(-timestamp.Accuracy), timestamp.Value.Add(timestamp.Accuracy))
for _, cert := range signerInfo.CertificateChain {
if !timestamp.BoundedAfter(cert.NotBefore) {
return fmt.Errorf("timestamp can be before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z))
}
if !timestamp.BoundedBefore(cert.NotAfter) {
return fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z))
}
}

// success
return nil
}
Loading