Skip to content

Commit 14a3285

Browse files
Patrick ZhengFeynmanZhou
authored andcommitted
feat: Timestamp (notaryproject#978)
Signed-off-by: Patrick Zheng <patrickzheng@microsoft.com>
1 parent 7eb6013 commit 14a3285

36 files changed

Lines changed: 649 additions & 83 deletions

cmd/notation/cert/add.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ Example - Add a certificate to the "ca" type of a named store "acme-rockets":
4848
4949
Example - Add a certificate to the "signingAuthority" type of a named store "wabbit-networks":
5050
notation cert add --type signingAuthority --store wabbit-networks wabbit-networks.pem
51+
52+
Example - Add a certificate to the "tsa" type of a named store "timestamp":
53+
notation cert add --type tsa --store timestamp wabbit-networks-timestamp.pem
5154
`,
5255
RunE: func(cmd *cobra.Command, args []string) error {
5356
return addCerts(opts)

cmd/notation/cert/delete.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ Example - Delete certificate "cert1.pem" with "signingAuthority" type from trust
5959
6060
Example - Delete all certificates with "ca" type from the trust store "acme-rockets", without prompt for confirmation:
6161
notation cert delete --type ca --store acme-rockets -y --all
62+
63+
Example - Delete certificate "wabbit-networks-timestamp.pem" with "tsa" type from trust store timestamp:
64+
notation cert delete --type tsa --store timestamp wabbit-networks-timestamp.pem -y
6265
`,
6366
RunE: func(cmd *cobra.Command, args []string) error {
6467
return deleteCerts(opts)

cmd/notation/cert/list.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ Example - List all certificate files from trust store of type "ca"
5454
5555
Example - List all certificate files from trust store "wabbit-networks" of type "signingAuthority"
5656
notation cert ls --type signingAuthority --store "wabbit-networks"
57+
58+
Example - List all certificate files from trust store of type "tsa"
59+
notation cert ls --type tsa
5760
`,
5861
RunE: func(cmd *cobra.Command, args []string) error {
5962
return listCerts(cmd.Context(), opts)

cmd/notation/cert/show.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ Example - Show details of certificate "cert1.pem" with type "ca" from trust stor
5757
5858
Example - Show details of certificate "cert2.pem" with type "signingAuthority" from trust store "wabbit-networks":
5959
notation cert show --type signingAuthority --store wabbit-networks cert2.pem
60+
61+
Example - Show details of certificate "wabbit-networks-timestamp.pem" with type "tsa" from trust store "timestamp":
62+
notation cert show --type tsa --store timestamp wabbit-networks-timestamp.pem
6063
`,
6164
RunE: func(cmd *cobra.Command, args []string) error {
6265
return showCerts(cmd.Context(), opts)

cmd/notation/sign.go

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,47 @@
1414
package main
1515

1616
import (
17+
"crypto/x509"
1718
"errors"
1819
"fmt"
20+
"net/http"
1921
"os"
2022
"strings"
2123
"time"
2224

25+
corex509 "github.com/notaryproject/notation-core-go/x509"
2326
"github.com/notaryproject/notation-go"
2427
"github.com/notaryproject/notation/cmd/notation/internal/experimental"
2528
"github.com/notaryproject/notation/internal/cmd"
2629
"github.com/notaryproject/notation/internal/envelope"
30+
"github.com/notaryproject/notation/internal/httputil"
31+
nx509 "github.com/notaryproject/notation/internal/x509"
32+
"github.com/notaryproject/tspclient-go"
2733
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
2834
"github.com/spf13/cobra"
35+
"golang.org/x/net/context"
2936
)
3037

3138
const referrersTagSchemaDeleteError = "failed to delete dangling referrers index"
3239

40+
// timestampingTimeout is the timeout when requesting timestamp countersignature
41+
// from a TSA
42+
const timestampingTimeout = 15 * time.Second
43+
3344
type signOpts struct {
3445
cmd.LoggingFlagOpts
3546
cmd.SignerFlagOpts
3647
SecureFlagOpts
37-
expiry time.Duration
38-
pluginConfig []string
39-
userMetadata []string
40-
reference string
41-
allowReferrersAPI bool
42-
forceReferrersTag bool
43-
ociLayout bool
44-
inputType inputType
48+
expiry time.Duration
49+
pluginConfig []string
50+
userMetadata []string
51+
reference string
52+
allowReferrersAPI bool
53+
forceReferrersTag bool
54+
ociLayout bool
55+
inputType inputType
56+
tsaServerURL string
57+
tsaRootCertificatePath string
4558
}
4659

4760
func signCommand(opts *signOpts) *cobra.Command {
@@ -74,6 +87,9 @@ Example - Sign an OCI artifact stored in a registry and specify the signature ex
7487
7588
Example - Sign an OCI artifact and store signature using the Referrers API. If it's not supported, fallback to the Referrers tag schema
7689
notation sign --force-referrers-tag=false <registry>/<repository>@<digest>
90+
91+
Example - Sign an OCI artifact with timestamping:
92+
notation sign --timestamp-url <TSA_url> --timestamp-root-cert <TSA_root_certificate_filepath> <registry>/<repository>@<digest>
7793
`
7894
experimentalExamples := `
7995
Example - [Experimental] Sign an OCI artifact referenced in an OCI layout
@@ -101,6 +117,16 @@ Example - [Experimental] Sign an OCI artifact identified by a tag and referenced
101117
return experimental.CheckFlagsAndWarn(cmd, "allow-referrers-api", "oci-layout")
102118
},
103119
RunE: func(cmd *cobra.Command, args []string) error {
120+
// timestamping
121+
if cmd.Flags().Changed("timestamp-url") {
122+
if opts.tsaServerURL == "" {
123+
return errors.New("timestamping: tsa url cannot be empty")
124+
}
125+
if opts.tsaRootCertificatePath == "" {
126+
return errors.New("timestamping: tsa root certificate path cannot be empty")
127+
}
128+
}
129+
104130
// allow-referrers-api flag is set
105131
if cmd.Flags().Changed("allow-referrers-api") {
106132
if opts.allowReferrersAPI {
@@ -120,9 +146,12 @@ Example - [Experimental] Sign an OCI artifact identified by a tag and referenced
120146
cmd.SetPflagPluginConfig(command.Flags(), &opts.pluginConfig)
121147
cmd.SetPflagUserMetadata(command.Flags(), &opts.userMetadata, cmd.PflagUserMetadataSignUsage)
122148
cmd.SetPflagReferrersAPI(command.Flags(), &opts.allowReferrersAPI, fmt.Sprintf(cmd.PflagReferrersUsageFormat, "sign"))
149+
command.Flags().StringVar(&opts.tsaServerURL, "timestamp-url", "", "RFC 3161 Timestamping Authority (TSA) server URL")
150+
command.Flags().StringVar(&opts.tsaRootCertificatePath, "timestamp-root-cert", "", "filepath of timestamp authority root certificate")
123151
cmd.SetPflagReferrersTag(command.Flags(), &opts.forceReferrersTag, "force to store signatures using the referrers tag schema")
124152
command.Flags().BoolVar(&opts.ociLayout, "oci-layout", false, "[Experimental] sign the artifact stored as OCI image layout")
125153
command.MarkFlagsMutuallyExclusive("oci-layout", "force-referrers-tag", "allow-referrers-api")
154+
command.MarkFlagsRequiredTogether("timestamp-url", "timestamp-root-cert")
126155
experimental.HideFlags(command, experimentalExamples, []string{"oci-layout"})
127156
return command
128157
}
@@ -140,7 +169,7 @@ func runSign(command *cobra.Command, cmdOpts *signOpts) error {
140169
if err != nil {
141170
return err
142171
}
143-
signOpts, err := prepareSigningOpts(cmdOpts)
172+
signOpts, err := prepareSigningOpts(ctx, cmdOpts)
144173
if err != nil {
145174
return err
146175
}
@@ -168,7 +197,7 @@ func runSign(command *cobra.Command, cmdOpts *signOpts) error {
168197
return nil
169198
}
170199

171-
func prepareSigningOpts(opts *signOpts) (notation.SignOptions, error) {
200+
func prepareSigningOpts(ctx context.Context, opts *signOpts) (notation.SignOptions, error) {
172201
mediaType, err := envelope.GetEnvelopeMediaType(opts.SignerFlagOpts.SignatureFormat)
173202
if err != nil {
174203
return notation.SignOptions{}, err
@@ -189,5 +218,36 @@ func prepareSigningOpts(opts *signOpts) (notation.SignOptions, error) {
189218
},
190219
UserMetadata: userMetadata,
191220
}
221+
if opts.tsaServerURL != "" {
222+
// timestamping
223+
fmt.Printf("Configured to timestamp with TSA %q\n", opts.tsaServerURL)
224+
signOpts.Timestamper, err = tspclient.NewHTTPTimestamper(httputil.NewClient(ctx, &http.Client{Timeout: timestampingTimeout}), opts.tsaServerURL)
225+
if err != nil {
226+
return notation.SignOptions{}, fmt.Errorf("cannot get http timestamper for timestamping: %w", err)
227+
}
228+
229+
rootCerts, err := corex509.ReadCertificateFile(opts.tsaRootCertificatePath)
230+
if err != nil {
231+
return notation.SignOptions{}, err
232+
}
233+
if len(rootCerts) == 0 {
234+
return notation.SignOptions{}, fmt.Errorf("cannot find any certificate from %q. Expecting single x509 root certificate in PEM or DER format from the file", opts.tsaRootCertificatePath)
235+
}
236+
if len(rootCerts) > 1 {
237+
return notation.SignOptions{}, fmt.Errorf("found more than one certificates from %q. Expecting single x509 root certificate in PEM or DER format from the file", opts.tsaRootCertificatePath)
238+
}
239+
tsaRootCert := rootCerts[0]
240+
isRoot, err := nx509.IsRootCertificate(tsaRootCert)
241+
if err != nil {
242+
return notation.SignOptions{}, fmt.Errorf("failed to check root certificate with error: %w", err)
243+
}
244+
if !isRoot {
245+
return notation.SignOptions{}, fmt.Errorf("certificate from %q is not a root certificate. Expecting single x509 root certificate in PEM or DER format from the file", opts.tsaRootCertificatePath)
246+
247+
}
248+
rootCAs := x509.NewCertPool()
249+
rootCAs.AddCert(tsaRootCert)
250+
signOpts.TSARootCAs = rootCAs
251+
}
192252
return signOpts, nil
193253
}

go.mod

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@ module github.com/notaryproject/notation
33
go 1.22
44

55
require (
6-
github.com/notaryproject/notation-core-go v1.0.3
7-
github.com/notaryproject/notation-go v1.1.1
6+
github.com/notaryproject/notation-core-go v1.0.4-0.20240716001320-f45197cbd53b
7+
github.com/notaryproject/notation-go v1.1.1-0.20240719045753-83409204754a
8+
github.com/notaryproject/tspclient-go v0.1.1-0.20240715235637-df25ef8d2172
89
github.com/opencontainers/go-digest v1.0.0
910
github.com/opencontainers/image-spec v1.1.0
1011
github.com/sirupsen/logrus v1.9.3
1112
github.com/spf13/cobra v1.8.1
1213
github.com/spf13/pflag v1.0.5
14+
golang.org/x/net v0.22.0
1315
golang.org/x/term v0.22.0
1416
oras.land/oras-go/v2 v2.5.0
1517
)
1618

1719
require (
1820
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
19-
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
21+
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
2022
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
2123
github.com/go-ldap/ldap/v3 v3.4.8 // indirect
2224
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
@@ -25,8 +27,8 @@ require (
2527
github.com/notaryproject/notation-plugin-framework-go v1.0.0 // indirect
2628
github.com/veraison/go-cose v1.1.0 // indirect
2729
github.com/x448/float16 v0.8.4 // indirect
28-
golang.org/x/crypto v0.23.0 // indirect
29-
golang.org/x/mod v0.17.0 // indirect
30+
golang.org/x/crypto v0.25.0 // indirect
31+
golang.org/x/mod v0.19.0 // indirect
3032
golang.org/x/sync v0.6.0 // indirect
3133
golang.org/x/sys v0.22.0 // indirect
3234
)

go.sum

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
66
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
77
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
88
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9-
github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA=
10-
github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
9+
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
10+
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
1111
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
1212
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
1313
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
@@ -35,12 +35,14 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
3535
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
3636
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
3737
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
38-
github.com/notaryproject/notation-core-go v1.0.3 h1:FCgvULSypEFrrNgvDRdHbKAGAgbXK43n/jKD9q2WECA=
39-
github.com/notaryproject/notation-core-go v1.0.3/go.mod h1:eDo5/LTUp23mB7w0CckJLnl+p93oGdyiKDzzggpqTH4=
40-
github.com/notaryproject/notation-go v1.1.1 h1:EAY8ERBWhrdaG9MIumSZ9xyUHktgr6OkCByd75HR+FA=
41-
github.com/notaryproject/notation-go v1.1.1/go.mod h1:XykI2i5jHb6cGf+bcG/cIeNfNO2u4Xoy2mkuOKHjVVI=
38+
github.com/notaryproject/notation-core-go v1.0.4-0.20240716001320-f45197cbd53b h1:uJ4bmNieZRkPj3UgmKr3bZr8vs7UJ2MdlJMeB0oOaZw=
39+
github.com/notaryproject/notation-core-go v1.0.4-0.20240716001320-f45197cbd53b/go.mod h1:MdxSbL9F5h63EmtXWfYMWy7hEmGmOmsfN4B6KM2WyhY=
40+
github.com/notaryproject/notation-go v1.1.1-0.20240719045753-83409204754a h1:o3kYOcQii0dMaDKdxnr1wPlEskXHHkDZDDb3kuss+W0=
41+
github.com/notaryproject/notation-go v1.1.1-0.20240719045753-83409204754a/go.mod h1:FwHtZC29bBvFdJu0NYM5MHxSrHJGwhkPRvEgevNo9wo=
4242
github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+1gTZWuJAZvxh3p8Lryjn5FaLzi4=
4343
github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics=
44+
github.com/notaryproject/tspclient-go v0.1.1-0.20240715235637-df25ef8d2172 h1:Q8UsmeFMzyFuMMq4dlbIRJUi7khEKXKUe2H2Hm3W92Y=
45+
github.com/notaryproject/tspclient-go v0.1.1-0.20240715235637-df25ef8d2172/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs=
4446
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
4547
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
4648
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
@@ -73,12 +75,12 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
7375
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
7476
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
7577
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
76-
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
77-
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
78+
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
79+
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
7880
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
7981
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
80-
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
81-
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
82+
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
83+
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
8284
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
8385
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
8486
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=

internal/httputil/client.go

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,50 @@ import (
2222
"oras.land/oras-go/v2/registry/remote/auth"
2323
)
2424

25-
// NewAuthClient returns an *auth.Client
25+
var userAgent = "notation/" + version.GetVersion()
26+
27+
// NewAuthClient returns an *auth.Client with debug log and user agent set
2628
func NewAuthClient(ctx context.Context, httpClient *http.Client) *auth.Client {
29+
httpClient = trace.SetHTTPDebugLog(ctx, httpClient)
2730
client := &auth.Client{
2831
Client: httpClient,
2932
Cache: auth.NewCache(),
3033
ClientID: "notation",
3134
}
32-
client.SetUserAgent("notation/" + version.GetVersion())
33-
trace.SetHTTPDebugLog(ctx, client)
35+
client.SetUserAgent(userAgent)
36+
return client
37+
}
38+
39+
// NewClient returns an *http.Client with debug log and user agent set
40+
func NewClient(ctx context.Context, client *http.Client) *http.Client {
41+
client = trace.SetHTTPDebugLog(ctx, client)
42+
return SetUserAgent(client)
43+
}
44+
45+
type userAgentTransport struct {
46+
base http.RoundTripper
47+
}
48+
49+
// RoundTrip returns t.Base.RoundTrip with user agent set in the request Header
50+
func (t *userAgentTransport) RoundTrip(req *http.Request) (*http.Response, error) {
51+
r := req.Clone(req.Context())
52+
if r.Header == nil {
53+
r.Header = http.Header{}
54+
}
55+
r.Header.Set("User-Agent", userAgent)
56+
return t.base.RoundTrip(r)
57+
}
58+
59+
// SetUserAgent sets the user agent for all out-going requests.
60+
func SetUserAgent(client *http.Client) *http.Client {
61+
if client == nil {
62+
client = &http.Client{}
63+
}
64+
if client.Transport == nil {
65+
client.Transport = http.DefaultTransport
66+
}
67+
client.Transport = &userAgentTransport{
68+
base: client.Transport,
69+
}
3470
return client
3571
}

internal/testdata/intermediate.pem

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICyjCCAbKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
3+
MCAXDTIyMDYzMDE5MjAwM1oYDzMwMjExMDMxMTkyMDAzWjAYMRYwFAYDVQQDDA1J
4+
bnRlcm1lZGlhdGUxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1JTs
5+
aiC/7+bho43kMVyHDwCsuocYp4PvYahB59NsKDR4QbrImU5ziaQ94D0DQqthe9pm
6+
qOW0SxN/vSRJAZFELxacrB9hc1y4MjiDYaRSt/LVx7astylBV/QRpmxWSEqp0Avu
7+
6nMJivIa1sD0WIEchizx6jG9BI5ULr9LbJICYvMgDalQR+0JGG+rKWnf1mPZyxEu
8+
9zEh215LCg5K56P3W5kC8fKBXSdSgTqZAvHzp6u78qet9S8gARtOEfS03A/7y7MC
9+
U0Sn2wdQyQdci0PBsR2sTZvUw179Cr93r5aRbb3I6jXgMWHAP2vvIndb9CM9ePyY
10+
yEy4Je7oWVVfMQ3CWQIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud
11+
DwEB/wQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEALR0apUQVbWGmagLUz4Y/bRsl
12+
mY9EJJXCiLuSxVWd3offjZfQTlGkQkCAW9FOQnm7JhEtaaHF1+AEVLo56/Gsd/hk
13+
sXsrBagYGi72jun7QTb6j7iZ3X9zanrP3SjdkpjVnqxRfH83diSh0r68Xruq1NSK
14+
qhUy1V+KQaXF0SSEutPqdTCoXUyxyXohVLU78uqZX/jx9Nc1XDuW9AZd+hMsLdk8
15+
qGJqHYFvj2vOHGMTeYk8dWgMBthQeL0wdsg2AvKtAvn6FQXCN7mKCWjpFTtYsU8v
16+
NsesS9M/i+geJjR/8/DDT3RP7S100BtCMm4XfHfmKcjXVaBh5evQVqGsa6TKLw==
17+
-----END CERTIFICATE-----
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADBDMQswCQYDVQQGEwJVUzEJ
3+
MAcGA1UECBMAMQkwBwYDVQQHEwAxDzANBgNVBAoTBk5vdGFyeTENMAsGA1UEAxME
4+
dGVzdDAeFw0yNDA3MjIwNTIwMzZaFw0yNDA4MjIwNTIwMzZaMEwxCzAJBgNVBAYT
5+
AlVTMQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHU2VhdHRsZTEPMA0GA1UEChMGTm90
6+
YXJ5MQ0wCwYDVQQDEwR0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
7+
AQEAp7XmYGf3p4JS/y5v6AIc/TxQvPTwIRxVmctNmDm5kG3LDUoGAAJbicTUfI/0
8+
Un38j/PlHNKQz9hKPwV+oYotKuQrVhaA2fft+INl36tvgCAPr8yX3ToOMCLr/UlT
9+
zQ7o9TB7IpnVT9DR9uik9MWfkz0Db5ARG1POquvSy2QM5wseEA58313YJ/7Em/Cq
10+
FCH5s9THCfQKpb09MZ/RTEggNqU4zGADah8e1KieYeZntM/hrw7sW5oeUueKG4D4
11+
3kvL8o7n1k6C+w8LwaOGhYXCQ51JxTE3lnmTrDdFRuKGObpNFNbLxdJPVLuHT1Nu
12+
bwVxj5APBJQyEyja3jJ9qLQANwIDAQABo1owWDAOBgNVHQ8BAf8EBAMCAgQwEwYD
13+
VR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQU
14+
yPScYtI4hs0+ibHaRV9BsgY734AwDQYJKoZIhvcNAQELBQADggEBABJHh3NELq1b
15+
jcJiJX76DwDTx+FGGN96/+T5622FGg1kHeAwuxS6pQODJNrVofbrhGAqaXTDT/Tz
16+
0b0AA5XCohmBFZQRwMh+C5QkFiIcZ9VMMBc6KTQT8DEgjI6Qo/OW2TDGOoFuAhmh
17+
4a1ACHszuHS55Th+0TKLqeZNA6DnL9IBm0RX1FJXbqhjX52ZnRH3Zqe7uML+kxKt
18+
LUdfnxHrpA1G2ugyAj+K7K6vth5QpezwCS1PZD2s5vlJd6clawxm5qRyyU46ow/y
19+
7bpTSEyg6PIWWh/qv4O2t4NMa1OoRkIXx/ppsKH9XwbRg/WZ0VWlGVS6GxBtLSpG
20+
tkyaxSRLdz0=
21+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)