Skip to content

Commit

Permalink
feat: Timestamp (notaryproject#418)
Browse files Browse the repository at this point in the history
Signed-off-by: Patrick Zheng <[email protected]>
  • Loading branch information
Two-Hearts authored Jul 15, 2024
1 parent 1c3e378 commit b525831
Show file tree
Hide file tree
Showing 38 changed files with 1,258 additions and 142 deletions.
4 changes: 4 additions & 0 deletions config/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"testing"

"github.com/notaryproject/notation-go/dir"
Expand All @@ -33,6 +34,9 @@ func TestLoadNonExistentFile(t *testing.T) {
}

func TestLoadSymlink(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on Windows")
}
root := t.TempDir()
dir.UserConfigDir = root
fileName := "symlink"
Expand Down
6 changes: 3 additions & 3 deletions example_localVerify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (

// examplePolicyDocument is an example of a valid trust policy document.
// trust policy document should follow this spec:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/trust-store-trust-policy.md#trust-policy
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy
var examplePolicyDocument = trustpolicy.Document{
Version: "1.0",
TrustPolicies: []trustpolicy.TrustPolicy{
Expand Down Expand Up @@ -75,7 +75,7 @@ func Example_localVerify() {
// createTrustStore creates a trust store directory for demo purpose.
// Users could use the default trust store from Notary and add trusted
// certificates into it following the trust store spec:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/trust-store-trust-policy.md#trust-store
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-store
if err := createTrustStore(); err != nil {
panic(err) // Handle error
}
Expand Down Expand Up @@ -173,7 +173,7 @@ func createTrustStore() error {
// Users should replace `exampleX509Certificate` with their own trusted
// certificate and add to the trust store, following the
// Notary certificate requirements:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/signature-specification.md#certificate-requirements
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements
exampleX509Certificate := `-----BEGIN CERTIFICATE-----
MIIDQDCCAiigAwIBAgIBUTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL
MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP
Expand Down
10 changes: 5 additions & 5 deletions example_remoteVerify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func Example_remoteVerify() {

// examplePolicyDocument is an example of a valid trust policy document.
// trust policy document should follow this spec:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/trust-store-trust-policy.md#trust-policy
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy
examplePolicyDocument := trustpolicy.Document{
Version: "1.0",
TrustPolicies: []trustpolicy.TrustPolicy{
Expand All @@ -52,9 +52,9 @@ func Example_remoteVerify() {
}

// generateTrustStore generates a trust store directory for demo purpose.
// Users could use the default trust store from Notary and add trusted
// certificates into it following the trust store spec:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/trust-store-trust-policy.md#trust-store
// Users should configure their own trust store and add trusted certificates
// into it following the trust store spec:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-store
if err := generateTrustStore(); err != nil {
panic(err) // Handle error
}
Expand Down Expand Up @@ -102,7 +102,7 @@ func generateTrustStore() error {
// Users should replace `exampleX509Certificate` with their own trusted
// certificate and add to the trust store, following the
// Notary certificate requirements:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/signature-specification.md#certificate-requirements
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements
exampleX509Certificate := `-----BEGIN CERTIFICATE-----
MIIDQDCCAiigAwIBAgIBUTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL
MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP
Expand Down
99 changes: 99 additions & 0 deletions example_signWithTimestmap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright The Notary Project Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package notation_test

import (
"context"
"crypto/x509"
"encoding/pem"
"fmt"

"oras.land/oras-go/v2/registry/remote"

"github.com/notaryproject/notation-core-go/testhelper"
"github.com/notaryproject/notation-go"
"github.com/notaryproject/notation-go/registry"
"github.com/notaryproject/notation-go/signer"
"github.com/notaryproject/tspclient-go"
)

// Example_signWithTimestamp demonstrates how to use notation.Sign to sign an
// artifact with a RFC 3161 compliant timestamp countersignature and
// user trusted TSA root certificate
func Example_signWithTimestamp() {
// exampleArtifactReference is an example of the target artifact reference
var exampleArtifactReference = "localhost:5000/software@sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e"

// exampleCertTuple contains a RSA privateKey and a self-signed X509
// certificate generated for demo purpose ONLY.
exampleCertTuple := testhelper.GetRSASelfSignedSigningCertTuple("Notation Example self-signed")
exampleCerts := []*x509.Certificate{exampleCertTuple.Cert}

// exampleSigner is a notation.Signer given key and X509 certificate chain.
// Users should replace `exampleCertTuple.PrivateKey` with their own private
// key and replace `exampleCerts` with the corresponding full certificate
// chain, following the Notary certificate requirements:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements
exampleSigner, err := signer.NewGenericSigner(exampleCertTuple.PrivateKey, exampleCerts)
if err != nil {
panic(err) // Handle error
}

// exampleRepo is an example of registry.Repository.
remoteRepo, err := remote.NewRepository(exampleArtifactReference)
if err != nil {
panic(err) // Handle error
}
exampleRepo := registry.NewRepository(remoteRepo)

// replace exampleRFC3161TSAServer with your trusted TSA server URL.
exampleRFC3161TSAServer := "<TSA server URL>"
httpTimestamper, err := tspclient.NewHTTPTimestamper(nil, exampleRFC3161TSAServer)
if err != nil {
panic(err) // Handle error
}

// replace exampleTSARootCertPem with your trusted TSA root cert.
exampleTSARootCertPem := "<TSA root cert>"
block, _ := pem.Decode([]byte(exampleTSARootCertPem))
if block == nil {
panic("failed to parse tsa root certificate PEM")
}
tsaRootCert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
panic("failed to parse tsa root certificate: " + err.Error())
}
tsaRootCAs := x509.NewCertPool()
tsaRootCAs.AddCert(tsaRootCert)

// exampleSignOptions is an example of notation.SignOptions.
exampleSignOptions := notation.SignOptions{
SignerSignOptions: notation.SignerSignOptions{
SignatureMediaType: exampleSignatureMediaType,
Timestamper: httpTimestamper,
TSARootCAs: tsaRootCAs,
},
ArtifactReference: exampleArtifactReference,
}

targetDesc, err := notation.Sign(context.Background(), exampleSigner, exampleRepo, exampleSignOptions)
if err != nil {
panic(err) // Handle error
}

fmt.Println("Successfully signed")
fmt.Println("targetDesc MediaType:", targetDesc.MediaType)
fmt.Println("targetDesc Digest:", targetDesc.Digest)
fmt.Println("targetDesc Size:", targetDesc.Size)
}
192 changes: 192 additions & 0 deletions example_verifyWithTimestamp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
// Copyright The Notary Project Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package notation_test

import (
"context"
"fmt"
"os"

_ "github.com/notaryproject/notation-core-go/signature/cose"
_ "github.com/notaryproject/notation-core-go/signature/jws"
"github.com/notaryproject/notation-go"
"github.com/notaryproject/notation-go/dir"
"github.com/notaryproject/notation-go/registry"
"github.com/notaryproject/notation-go/verifier"
"github.com/notaryproject/notation-go/verifier/trustpolicy"
"github.com/notaryproject/notation-go/verifier/truststore"
"oras.land/oras-go/v2/registry/remote"
)

// Example_verifyWithTimestamp demonstrates how to use notation.Verify to verify
// signature of an artifact including RFC 3161 compliant timestamp countersignature
func Example_verifyWithTimestamp() {
// exampleArtifactReference is an example of the target artifact reference
exampleArtifactReference := "localhost:5000/software@sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e"

// examplePolicyDocument is an example of a valid trust policy document with
// timestamping configurations.
// trust policy document should follow this spec:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy
examplePolicyDocument := trustpolicy.Document{
Version: "1.0",
TrustPolicies: []trustpolicy.TrustPolicy{
{
Name: "test-statement-name",
RegistryScopes: []string{"*"},
SignatureVerification: trustpolicy.SignatureVerification{
VerificationLevel: trustpolicy.LevelStrict.Name,

// verify timestamp countersignature only if the signing
// certificate chain has expired.
// Default: trustpolicy.OptionAlways
VerifyTimestamp: trustpolicy.OptionAfterCertExpiry,
},

// `tsa` trust store type MUST be configured to enable
// timestamp verification
TrustStores: []string{"ca:valid-trust-store", "tsa:valid-tsa"},

// TrustedIdentities only contains trusted identities of `ca`
// and `signingAuthority`
TrustedIdentities: []string{"*"},
},
},
}

// generateTrustStoreWithTimestamp generates a trust store directory for demo purpose.
// Users should configure their own trust store and add trusted certificates
// into it following the trust store spec:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-store
if err := generateTrustStoreWithTimestamp(); err != nil {
panic(err) // Handle error
}

// exampleVerifier is an example of notation.Verifier given
// trust policy document and X509 trust store.
exampleVerifier, err := verifier.New(&examplePolicyDocument, truststore.NewX509TrustStore(dir.ConfigFS()), nil)
if err != nil {
panic(err) // Handle error
}

// exampleRepo is an example of registry.Repository.
remoteRepo, err := remote.NewRepository(exampleArtifactReference)
if err != nil {
panic(err) // Handle error
}
exampleRepo := registry.NewRepository(remoteRepo)

// exampleVerifyOptions is an example of notation.VerifyOptions.
exampleVerifyOptions := notation.VerifyOptions{
ArtifactReference: exampleArtifactReference,
MaxSignatureAttempts: 50,
}

// remote verify core process
// upon successful verification, the target manifest descriptor
// and signature verification outcome are returned.
targetDesc, _, err := notation.Verify(context.Background(), exampleVerifier, exampleRepo, exampleVerifyOptions)
if err != nil {
panic(err) // Handle error
}

fmt.Println("Successfully verified")
fmt.Println("targetDesc MediaType:", targetDesc.MediaType)
fmt.Println("targetDesc Digest:", targetDesc.Digest)
fmt.Println("targetDesc Size:", targetDesc.Size)
}

func generateTrustStoreWithTimestamp() error {
// changing the path of the trust store for demo purpose.
// Users could keep the default value, i.e. os.UserConfigDir.
dir.UserConfigDir = "tmp"

// an example of a valid X509 self-signed certificate for demo purpose ONLY.
// Users should replace `exampleX509Certificate` with their own trusted
// certificate and add to the trust store, following the
// Notary certificate requirements:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements
exampleX509Certificate := `-----BEGIN CERTIFICATE-----
MIIDQDCCAiigAwIBAgIBUTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL
MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP
MA0GA1UEAxMGYWxwaW5lMCAXDTAwMDgyOTEzNTAwMFoYDzIxMjMwODI5MTM1MDAw
WjBOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUx
DzANBgNVBAoTBk5vdGFyeTEPMA0GA1UEAxMGYWxwaW5lMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAocg3qEsyNDDLfB8OHD4dhi+M1NPK1Asy5NX84c+g
vacZuoPLTwmpOfm6nPt7GPPB9G7S6xxhFNbRxTYfYUjK+kaCj38XjBRf5lGewbSJ
KVkxQ82/axU70ceSW3JpazrageN9JUTZ/Jfi4MfnipITwcmMoiij8eGrHskjyVyZ
bJd0WMMKRDWVhLPUiPMVWt/4d7YtZItzacaQKtXmXgsTCTWpIols3gftNYjrQoMs
UelUdD8vOAWN9J28/SyC+uSh/K1KfyUlbqufn4di8DEBxntP5wnXYbJL1jtjsUgE
xAVjQxT1zI59X36m3t3YKqCQh1cud02L5onObY6zj57N6QIDAQABoycwJTAOBgNV
HQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQAD
ggEBAC8AjBLy7EsRpi6oguCdFSb6nRGjvF17N+b6mDb3sARnB8T1pxvzTT26ya+A
yWR+jjodEwbMIS+13lV+9qT2LwqlbOUNY519Pa2GRRY72JjeowWI3iKkKaMzfZUB
7lRTGXdEuZApLbTO/3JVcR9ffu00N1UaAP9YGElSt4JDJYA9M+d/Qto+HiIsE0Kj
+jdnwIYovPPOlryKOLfFb/r1GEq7n63xFZz83iyWNaZdsJ5N3YHxdOpkbBbCalOE
BDJTjQKqeAYBLoANNU0OBslmqHCSBTEnhbqJHN6QKyF09ScOl5LwM1QsTl0UY5si
GLAfj/jSf9OH9VLTPHOS8/N0Ka4=
-----END CERTIFICATE-----`

// Adding the certificate into the trust store.
if err := os.MkdirAll("tmp/truststore/x509/ca/valid-trust-store", 0700); err != nil {
return err
}
if err := os.WriteFile("tmp/truststore/x509/ca/valid-trust-store/NotationExample.pem", []byte(exampleX509Certificate), 0600); err != nil {
return err
}

// an example of a valid TSA root certificate for demo purpose ONLY.
// Users should replace `exampleTSARootCertificate` with their own trusted
// TSA root certificate and add to the trust store, following the
// Notary certificate requirements:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements
exampleTSARootCertificate := `-----BEGIN CERTIFICATE-----
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y
ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If
xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV
ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO
DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ
jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/
CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi
EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM
fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY
uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK
chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t
9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2
SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd
+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc
fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa
sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N
cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N
0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie
4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI
r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm
gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
-----END CERTIFICATE-----`

// Adding the tsa root certificate into the trust store.
if err := os.MkdirAll("tmp/truststore/x509/tsa/valid-tsa", 0700); err != nil {
return err
}
return os.WriteFile("tmp/truststore/x509/tsa/valid-tsa/NotationTSAExample.pem", []byte(exampleTSARootCertificate), 0600)
}
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ go 1.21

require (
github.com/go-ldap/ldap/v3 v3.4.8
github.com/notaryproject/notation-core-go v1.0.3
github.com/notaryproject/notation-core-go v1.0.4-0.20240708015912-faac9b7f3f10
github.com/notaryproject/notation-plugin-framework-go v1.0.0
github.com/notaryproject/tspclient-go v0.1.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0
github.com/veraison/go-cose v1.1.0
Expand All @@ -16,7 +17,7 @@ require (

require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/google/uuid v1.6.0 // indirect
Expand Down
Loading

0 comments on commit b525831

Please sign in to comment.