diff --git a/security/advancedtls/advancedtls_test.go b/security/advancedtls/advancedtls_test.go index afad25e7cb4b..ce176df0bf35 100644 --- a/security/advancedtls/advancedtls_test.go +++ b/security/advancedtls/advancedtls_test.go @@ -25,6 +25,7 @@ import ( "errors" "fmt" "net" + "os" "testing" lru "github.com/hashicorp/golang-lru" @@ -371,6 +372,27 @@ func (s) TestClientServerHandshake(t *testing.T) { getRootCAsForServerBad := func(params *GetRootCAsParams) (*GetRootCAsResults, error) { return nil, fmt.Errorf("bad root certificate reloading") } + + getRootCAsForClientCRL := func(params *GetRootCAsParams) (*GetRootCAsResults, error) { + return &GetRootCAsResults{TrustCerts: cs.ClientTrust3}, nil + } + + getRootCAsForServerCRL := func(params *GetRootCAsParams) (*GetRootCAsResults, error) { + return &GetRootCAsResults{TrustCerts: cs.ServerTrust3}, nil + } + + makeStaticCRLProvider := func(crlPath string) *RevocationConfig { + rawCRL, err := os.ReadFile(crlPath) + if err != nil { + t.Fatalf("readFile(%v) failed err = %v", crlPath, err) + } + cRLProvider := NewStaticCRLProvider([][]byte{rawCRL}) + return &RevocationConfig{ + AllowUndetermined: true, + CRLProvider: cRLProvider, + } + } + cache, err := lru.New(5) if err != nil { t.Fatalf("lru.New: err = %v", err) @@ -682,7 +704,7 @@ func (s) TestClientServerHandshake(t *testing.T) { }, // Client: set valid credentials with the revocation config // Server: set valid credentials with the revocation config - // Expected Behavior: success, because non of the certificate chains sent in the connection are revoked + // Expected Behavior: success, because none of the certificate chains sent in the connection are revoked { desc: "Client sets peer cert, reload root function with verifyFuncGood; Server sets peer cert, reload root function; mutualTLS", clientCert: []tls.Certificate{cs.ClientCert1}, @@ -704,6 +726,37 @@ func (s) TestClientServerHandshake(t *testing.T) { Cache: cache, }, }, + // Client: set valid credentials with the revocation config + // Server: set valid credentials with the revocation config + // Expected Behavior: success, because none of the certificate chains sent in the connection are revoked + { + desc: "Client sets peer cert, reload root function with verifyFuncGood; Server sets peer cert, reload root function; Client uses CRL; mutualTLS", + clientCert: []tls.Certificate{cs.ClientCert3}, + clientGetRoot: getRootCAsForClientCRL, + clientVerifyFunc: clientVerifyFuncGood, + clientVType: CertVerification, + clientRevocationConfig: makeStaticCRLProvider(testdata.Path("crl/provider_crl_empty.pem")), + serverMutualTLS: true, + serverCert: []tls.Certificate{cs.ServerCert3}, + serverGetRoot: getRootCAsForServerCRL, + serverVType: CertVerification, + }, + // Client: set valid credentials with the revocation config + // Server: set revoked credentials with the revocation config + // Expected Behavior: fail, server creds are revoked + { + desc: "Client sets peer cert, reload root function with verifyFuncGood; Server sets revoked cert; Client uses CRL; mutualTLS", + clientCert: []tls.Certificate{cs.ClientCert3}, + clientGetRoot: getRootCAsForClientCRL, + clientVerifyFunc: clientVerifyFuncGood, + clientVType: CertVerification, + clientRevocationConfig: makeStaticCRLProvider(testdata.Path("crl/provider_crl_server_revoked.pem")), + serverMutualTLS: true, + serverCert: []tls.Certificate{cs.ServerCert3}, + serverGetRoot: getRootCAsForServerCRL, + serverVType: CertVerification, + serverExpectError: true, + }, } { test := test t.Run(test.desc, func(t *testing.T) { diff --git a/security/advancedtls/crl.go b/security/advancedtls/crl.go index 207c7f81a2ef..4eea8395a061 100644 --- a/security/advancedtls/crl.go +++ b/security/advancedtls/crl.go @@ -65,6 +65,11 @@ type RevocationConfig struct { AllowUndetermined bool // Cache will store CRL files if not nil, otherwise files are reloaded for every lookup. Cache Cache + // CRLProvider is an alternative to using RootDir directly for the + // X509_LOOKUP_hash_dir approach to CRL files. If set, the CRLProvider's CRL + // function will be called when looking up and fetching CRLs during the + // handshake. + CRLProvider CRLProvider } // RevocationStatus is the revocation status for a certificate or chain. @@ -83,13 +88,46 @@ func (s RevocationStatus) String() string { return [...]string{"RevocationUndetermined", "RevocationUnrevoked", "RevocationRevoked"}[s] } -// certificateListExt contains a pkix.CertificateList and parsed -// extensions that aren't provided by the golang CRL parser. -type certificateListExt struct { - CertList *x509.RevocationList +// CRL contains a pkix.CertificateList and parsed extensions that aren't +// provided by the golang CRL parser. +// All CRLs should be loaded using NewCRL() for bytes directly or ReadCRLFile() +// to read directly from a filepath +type CRL struct { + certList *x509.RevocationList // RFC5280, 5.2.1, all conforming CRLs must have a AKID with the ID method. - AuthorityKeyID []byte - RawIssuer []byte + authorityKeyID []byte + rawIssuer []byte +} + +// NewCRL constructs new CRL from the provided byte array. +func NewCRL(b []byte) (*CRL, error) { + crl, err := parseRevocationList(b) + if err != nil { + return nil, fmt.Errorf("fail to parse CRL: %v", err) + } + crlExt, err := parseCRLExtensions(crl) + if err != nil { + return nil, fmt.Errorf("fail to parse CRL extensions: %v", err) + } + crlExt.rawIssuer, err = extractCRLIssuer(b) + if err != nil { + return nil, fmt.Errorf("fail to extract CRL issuer failed err= %v", err) + } + return crlExt, nil +} + +// ReadCRLFile reads a file from the provided path, and returns constructed CRL +// struct from it. +func ReadCRLFile(path string) (*CRL, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("cannot read file from provided path %q: %v", path, err) + } + crl, err := NewCRL(b) + if err != nil { + return nil, fmt.Errorf("cannot construct CRL from file %q: %v", path, err) + } + return crl, nil } const tagDirectoryName = 4 @@ -215,31 +253,31 @@ func checkChain(chain []*x509.Certificate, cfg RevocationConfig) RevocationStatu return chainStatus } -func cachedCrl(rawIssuer []byte, cache Cache) (*certificateListExt, bool) { +func cachedCrl(rawIssuer []byte, cache Cache) (*CRL, bool) { val, ok := cache.Get(hex.EncodeToString(rawIssuer)) if !ok { return nil, false } - crl, ok := val.(*certificateListExt) + crl, ok := val.(*CRL) if !ok { return nil, false } // If the CRL is expired, force a reload. - if hasExpired(crl.CertList, time.Now()) { + if hasExpired(crl.certList, time.Now()) { return nil, false } return crl, true } // fetchIssuerCRL fetches and verifies the CRL for rawIssuer from disk or cache if configured in cfg. -func fetchIssuerCRL(rawIssuer []byte, crlVerifyCrt []*x509.Certificate, cfg RevocationConfig) (*certificateListExt, error) { +func fetchIssuerCRL(rawIssuer []byte, crlVerifyCrt []*x509.Certificate, cfg RevocationConfig) (*CRL, error) { if cfg.Cache != nil { if crl, ok := cachedCrl(rawIssuer, cfg.Cache); ok { return crl, nil } } - crl, err := fetchCRL(rawIssuer, cfg) + crl, err := fetchCRLOpenSSLHashDir(rawIssuer, cfg) if err != nil { return nil, fmt.Errorf("fetchCRL() failed: %v", err) } @@ -253,21 +291,39 @@ func fetchIssuerCRL(rawIssuer []byte, crlVerifyCrt []*x509.Certificate, cfg Revo return crl, nil } +func fetchCRL(c *x509.Certificate, crlVerifyCrt []*x509.Certificate, cfg RevocationConfig) (*CRL, error) { + if cfg.CRLProvider != nil { + crl, err := cfg.CRLProvider.CRL(c) + if err != nil { + return nil, fmt.Errorf("CrlProvider failed err = %v", err) + } + if crl == nil { + return nil, fmt.Errorf("no CRL found for certificate's issuer") + } + return crl, nil + } + return fetchIssuerCRL(c.RawIssuer, crlVerifyCrt, cfg) +} + // checkCert checks a single certificate against the CRL defined in the certificate. // It will fetch and verify the CRL(s) defined in the root directory specified by cfg. // If we can't load any authoritative CRL files, the status is RevocationUndetermined. // c is the certificate to check. // crlVerifyCrt is the group of possible certificates to verify the crl. func checkCert(c *x509.Certificate, crlVerifyCrt []*x509.Certificate, cfg RevocationConfig) RevocationStatus { - crl, err := fetchIssuerCRL(c.RawIssuer, crlVerifyCrt, cfg) + crl, err := fetchCRL(c, crlVerifyCrt, cfg) if err != nil { - // We couldn't load any CRL files for the certificate, so we don't know if it's RevocationUnrevoked or not. - grpclogLogger.Warningf("getIssuerCRL(%v) err = %v", c.Issuer, err) + // We couldn't load any CRL files for the certificate, so we don't know + // if it's RevocationUnrevoked or not. This is not necessarily a + // problem - it's not invalid to have no CRLs if you don't have any + // revocations for an issuer. We just return RevocationUndetermined and + // there is a setting for the user to control the handling of that. + grpclogLogger.Warningf("fetchCRL() err = %v", err) return RevocationUndetermined } revocation, err := checkCertRevocation(c, crl) if err != nil { - grpclogLogger.Warningf("checkCertRevocation(CRL %v) failed: %v", crl.CertList.Issuer, err) + grpclogLogger.Warningf("checkCertRevocation(CRL %v) failed: %v", crl.certList.Issuer, err) // We couldn't check the CRL file for some reason, so we don't know if it's RevocationUnrevoked or not. return RevocationUndetermined } @@ -277,13 +333,13 @@ func checkCert(c *x509.Certificate, crlVerifyCrt []*x509.Certificate, cfg Revoca return revocation } -func checkCertRevocation(c *x509.Certificate, crl *certificateListExt) (RevocationStatus, error) { +func checkCertRevocation(c *x509.Certificate, crl *CRL) (RevocationStatus, error) { // Per section 5.3.3 we prime the certificate issuer with the CRL issuer. // Subsequent entries use the previous entry's issuer. - rawEntryIssuer := crl.RawIssuer + rawEntryIssuer := crl.rawIssuer // Loop through all the revoked certificates. - for _, revCert := range crl.CertList.RevokedCertificates { + for _, revCert := range crl.certList.RevokedCertificates { // 5.3 Loop through CRL entry extensions for needed information. for _, ext := range revCert.Extensions { if oidCertificateIssuer.Equal(ext.Id) { @@ -375,11 +431,11 @@ type issuingDistributionPoint struct { // parseCRLExtensions parses the extensions for a CRL // and checks that they're supported by the parser. -func parseCRLExtensions(c *x509.RevocationList) (*certificateListExt, error) { +func parseCRLExtensions(c *x509.RevocationList) (*CRL, error) { if c == nil { return nil, errors.New("c is nil, expected any value") } - certList := &certificateListExt{CertList: c} + certList := &CRL{certList: c} for _, ext := range c.Extensions { switch { @@ -393,7 +449,7 @@ func parseCRLExtensions(c *x509.RevocationList) (*certificateListExt, error) { } else if len(rest) != 0 { return nil, errors.New("trailing data after AKID extension") } - certList.AuthorityKeyID = a.ID + certList.authorityKeyID = a.ID case oidIssuingDistributionPoint.Equal(ext.Id): var dp issuingDistributionPoint @@ -418,14 +474,14 @@ func parseCRLExtensions(c *x509.RevocationList) (*certificateListExt, error) { } } - if len(certList.AuthorityKeyID) == 0 { + if len(certList.authorityKeyID) == 0 { return nil, errors.New("authority key identifier extension missing") } return certList, nil } -func fetchCRL(rawIssuer []byte, cfg RevocationConfig) (*certificateListExt, error) { - var parsedCRL *certificateListExt +func fetchCRLOpenSSLHashDir(rawIssuer []byte, cfg RevocationConfig) (*CRL, error) { + var parsedCRL *CRL // 6.3.3 (a) (1) (ii) // According to X509_LOOKUP_hash_dir the format is issuer_hash.rN where N is an increasing number. // There are no gaps, so we break when we can't find a file. @@ -449,7 +505,7 @@ func fetchCRL(rawIssuer []byte, cfg RevocationConfig) (*certificateListExt, erro // Parsing errors for a CRL shouldn't happen so fail. return nil, fmt.Errorf("parseRevocationList(%v) failed: %v", crlPath, err) } - var certList *certificateListExt + var certList *CRL if certList, err = parseCRLExtensions(crl); err != nil { grpclogLogger.Infof("fetchCRL: unsupported crl %v: %v", crlPath, err) // Continue to find a supported CRL @@ -460,7 +516,7 @@ func fetchCRL(rawIssuer []byte, cfg RevocationConfig) (*certificateListExt, erro if err != nil { return nil, err } - certList.RawIssuer = rawCRLIssuer + certList.rawIssuer = rawCRLIssuer // RFC5280, 6.3.3 (b) Verify the issuer and scope of the complete CRL. if bytes.Equal(rawIssuer, rawCRLIssuer) { parsedCRL = certList @@ -475,7 +531,7 @@ func fetchCRL(rawIssuer []byte, cfg RevocationConfig) (*certificateListExt, erro return parsedCRL, nil } -func verifyCRL(crl *certificateListExt, rawIssuer []byte, chain []*x509.Certificate) error { +func verifyCRL(crl *CRL, rawIssuer []byte, chain []*x509.Certificate) error { // RFC5280, 6.3.3 (f) Obtain and validateate the certification path for the issuer of the complete CRL // We intentionally limit our CRLs to be signed with the same certificate path as the certificate // so we can use the chain from the connection. @@ -487,12 +543,12 @@ func verifyCRL(crl *certificateListExt, rawIssuer []byte, chain []*x509.Certific // "Conforming CRL issuers MUST use the key identifier method, and MUST // include this extension in all CRLs issued." // So, this is much simpler than RFC4158 and should be compatible. - if bytes.Equal(c.SubjectKeyId, crl.AuthorityKeyID) && bytes.Equal(c.RawSubject, crl.RawIssuer) { + if bytes.Equal(c.SubjectKeyId, crl.authorityKeyID) && bytes.Equal(c.RawSubject, crl.rawIssuer) { // RFC5280, 6.3.3 (g) Validate signature. - return crl.CertList.CheckSignatureFrom(c) + return crl.certList.CheckSignatureFrom(c) } } - return fmt.Errorf("verifyCRL: No certificates mached CRL issuer (%v)", crl.CertList.Issuer) + return fmt.Errorf("verifyCRL: No certificates mached CRL issuer (%v)", crl.certList.Issuer) } // pemType is the type of a PEM encoded CRL. diff --git a/security/advancedtls/crl_provider.go b/security/advancedtls/crl_provider.go new file mode 100644 index 000000000000..590906169f35 --- /dev/null +++ b/security/advancedtls/crl_provider.go @@ -0,0 +1,238 @@ +/* + * + * Copyright 2023 gRPC 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 advancedtls + +import ( + "crypto/x509" + "fmt" + "os" + "sync" + "time" +) + +const defaultCRLRefreshDuration = 1 * time.Hour +const minCRLRefreshDuration = 1 * time.Minute + +// CRLProvider is the interface to be implemented to enable custom CRL provider +// behavior, as defined in [gRFC A69]. +// +// The interface defines how gRPC gets CRLs from the provider during handshakes, +// but doesn't prescribe a specific way to load and store CRLs. Such +// implementations can be used in RevocationConfig of advancedtls.ClientOptions +// and/or advancedtls.ServerOptions. +// Please note that checking CRLs is directly on the path of connection +// establishment, so implementations of the CRL function need to be fast, and +// slow things such as file IO should be done asynchronously. +// +// [gRFC A69]: https://github.com/grpc/proposal/pull/382 +type CRLProvider interface { + // CRL accepts x509 Cert and returns a related CRL struct, which can contain + // either an empty or non-empty list of revoked certificates. If an error is + // thrown or (nil, nil) is returned, it indicates that we can't load any + // authoritative CRL files (which may not necessarily be a problem). It's not + // considered invalid to have no CRLs if there are no revocations for an + // issuer. In such cases, the status of the check CRL operation is marked as + // RevocationUndetermined, as defined in [RFC5280 - Undetermined]. + // + // [RFC5280 - Undetermined]: https://datatracker.ietf.org/doc/html/rfc5280#section-6.3.3 + CRL(cert *x509.Certificate) (*CRL, error) +} + +// StaticCRLProvider implements CRLProvider interface by accepting raw content +// of CRL files at creation time and storing parsed CRL structs in-memory. +type StaticCRLProvider struct { + crls map[string]*CRL +} + +// NewStaticCRLProvider processes raw content of CRL files, adds parsed CRL +// structs into in-memory, and returns a new instance of the StaticCRLProvider. +func NewStaticCRLProvider(rawCRLs [][]byte) *StaticCRLProvider { + p := StaticCRLProvider{} + p.crls = make(map[string]*CRL) + for idx, rawCRL := range rawCRLs { + cRL, err := NewCRL(rawCRL) + if err != nil { + grpclogLogger.Warningf("Can't parse raw CRL number %v from the slice: %v", idx, err) + continue + } + p.addCRL(cRL) + } + return &p +} + +// AddCRL adds/updates provided CRL to in-memory storage. +func (p *StaticCRLProvider) addCRL(crl *CRL) { + key := crl.certList.Issuer.ToRDNSequence().String() + p.crls[key] = crl +} + +// CRL returns CRL struct if it was passed to NewStaticCRLProvider. +func (p *StaticCRLProvider) CRL(cert *x509.Certificate) (*CRL, error) { + return p.crls[cert.Issuer.ToRDNSequence().String()], nil +} + +// FileWatcherOptions represents a data structure holding a configuration for +// FileWatcherCRLProvider. +type FileWatcherOptions struct { + CRLDirectory string // Path of the directory containing CRL files + RefreshDuration time.Duration // Time interval between CRLDirectory scans, can't be smaller than 1 minute + CRLReloadingFailedCallback func(err error) // Custom callback executed when a CRL file can’t be processed +} + +// FileWatcherCRLProvider implements the CRLProvider interface by periodically +// scanning CRLDirectory (see FileWatcherOptions) and storing CRL structs +// in-memory. Users should call Close to stop the background refresh of +// CRLDirectory. +type FileWatcherCRLProvider struct { + crls map[string]*CRL + opts FileWatcherOptions + mu sync.Mutex + stop chan struct{} + done chan struct{} +} + +// NewFileWatcherCRLProvider returns a new instance of the +// FileWatcherCRLProvider. It uses FileWatcherOptions to validate and apply +// configuration required for creating a new instance. Users should call Close +// to stop the background refresh of CRLDirectory. +func NewFileWatcherCRLProvider(o FileWatcherOptions) (*FileWatcherCRLProvider, error) { + if err := o.validate(); err != nil { + return nil, err + } + provider := &FileWatcherCRLProvider{ + crls: make(map[string]*CRL), + opts: o, + stop: make(chan struct{}), + done: make(chan struct{}), + } + go provider.run() + return provider, nil +} + +func (o *FileWatcherOptions) validate() error { + // Checks relates to CRLDirectory. + if o.CRLDirectory == "" { + return fmt.Errorf("advancedtls: CRLDirectory needs to be specified") + } + if _, err := os.ReadDir(o.CRLDirectory); err != nil { + return fmt.Errorf("advancedtls: CRLDirectory %v is not readable: %v", o.CRLDirectory, err) + } + // Checks related to RefreshDuration. + if o.RefreshDuration == 0 { + o.RefreshDuration = defaultCRLRefreshDuration + } + if o.RefreshDuration < minCRLRefreshDuration { + grpclogLogger.Warningf("RefreshDuration must be at least 1 minute: provided value %v, minimum value %v will be used.", o.RefreshDuration, minCRLRefreshDuration) + o.RefreshDuration = minCRLRefreshDuration + } + return nil +} + +// Start starts watching the directory for CRL files and updates the provider accordingly. +func (p *FileWatcherCRLProvider) run() { + defer close(p.done) + ticker := time.NewTicker(p.opts.RefreshDuration) + defer ticker.Stop() + p.scanCRLDirectory() + + for { + select { + case <-p.stop: + grpclogLogger.Infof("Scanning of CRLDirectory %v stopped", p.opts.CRLDirectory) + return + case <-ticker.C: + p.scanCRLDirectory() + } + } +} + +// Close waits till the background refresh of CRLDirectory of +// FileWatcherCRLProvider is done and then stops it. +func (p *FileWatcherCRLProvider) Close() { + close(p.stop) + <-p.done +} + +// scanCRLDirectory starts the process of scanning +// FileWatcherOptions.CRLDirectory and updating in-memory storage of CRL +// structs, as defined in [gRFC A69]. It's called periodically +// (see FileWatcherOptions.RefreshDuration) by run goroutine. +// +// [gRFC A69]: https://github.com/grpc/proposal/pull/382 +func (p *FileWatcherCRLProvider) scanCRLDirectory() { + dir, err := os.Open(p.opts.CRLDirectory) + if err != nil { + grpclogLogger.Errorf("Can't open CRLDirectory %v", p.opts.CRLDirectory, err) + if p.opts.CRLReloadingFailedCallback != nil { + p.opts.CRLReloadingFailedCallback(err) + } + } + defer dir.Close() + + files, err := dir.ReadDir(0) + if err != nil { + grpclogLogger.Errorf("Can't access files under CRLDirectory %v", p.opts.CRLDirectory, err) + if p.opts.CRLReloadingFailedCallback != nil { + p.opts.CRLReloadingFailedCallback(err) + } + } + + tempCRLs := make(map[string]*CRL) + successCounter := 0 + failCounter := 0 + for _, file := range files { + filePath := fmt.Sprintf("%s/%s", p.opts.CRLDirectory, file.Name()) + crl, err := ReadCRLFile(filePath) + if err != nil { + failCounter++ + grpclogLogger.Warningf("Can't add CRL from file %v under CRLDirectory %v", filePath, p.opts.CRLDirectory, err) + if p.opts.CRLReloadingFailedCallback != nil { + p.opts.CRLReloadingFailedCallback(err) + } + continue + } + tempCRLs[crl.certList.Issuer.ToRDNSequence().String()] = crl + successCounter++ + } + // Only if all the files are processed successfully we can swap maps (there + // might be deletions of entries in this case). + if len(files) == successCounter { + p.mu.Lock() + defer p.mu.Unlock() + p.crls = tempCRLs + grpclogLogger.Infof("Scan of CRLDirectory %v completed, %v files found and processed successfully, in-memory CRL storage flushed and repopulated", p.opts.CRLDirectory, len(files)) + } else { + // Since some of the files failed we can only add/update entries in the map. + p.mu.Lock() + defer p.mu.Unlock() + for key, value := range tempCRLs { + p.crls[key] = value + } + grpclogLogger.Infof("Scan of CRLDirectory %v completed, %v files found, %v files processing failed, %v entries of in-memory CRL storage added/updated", p.opts.CRLDirectory, len(files), failCounter, successCounter) + } +} + +// CRL retrieves the CRL associated with the given certificate's issuer DN from +// in-memory if it was loaded during FileWatcherOptions.CRLDirectory scan before +// the execution of this function. +func (p *FileWatcherCRLProvider) CRL(cert *x509.Certificate) (*CRL, error) { + p.mu.Lock() + defer p.mu.Unlock() + return p.crls[cert.Issuer.ToRDNSequence().String()], nil +} diff --git a/security/advancedtls/crl_provider_test.go b/security/advancedtls/crl_provider_test.go new file mode 100644 index 000000000000..5245f58895ab --- /dev/null +++ b/security/advancedtls/crl_provider_test.go @@ -0,0 +1,354 @@ +/* + * + * Copyright 2023 gRPC 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 advancedtls + +import ( + "crypto/x509" + "fmt" + "io" + "os" + "path/filepath" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/security/advancedtls/testdata" +) + +// TestStaticCRLProvider tests how StaticCRLProvider handles the major four +// cases for CRL checks. It loads the CRLs under crl directory, constructs +// unrevoked, revoked leaf, and revoked intermediate chains, as well as a chain +// without CRL for issuer, and checks that it’s correctly processed. +func (s) TestStaticCRLProvider(t *testing.T) { + rawCRLs := make([][]byte, 6) + for i := 1; i <= 6; i++ { + rawCRL, err := os.ReadFile(testdata.Path(fmt.Sprintf("crl/%d.crl", i))) + if err != nil { + t.Fatalf("readFile(%v) failed err = %v", fmt.Sprintf("crl/%d.crl", i), err) + } + rawCRLs = append(rawCRLs, rawCRL) + } + p := NewStaticCRLProvider(rawCRLs) + // Each test data entry contains a description of a certificate chain, + // certificate chain itself, and if CRL is not expected to be found. + tests := []struct { + desc string + certs []*x509.Certificate + expectNoCRL bool + }{ + { + desc: "Unrevoked chain", + certs: makeChain(t, testdata.Path("crl/unrevoked.pem")), + }, + { + desc: "Revoked Intermediate chain", + certs: makeChain(t, testdata.Path("crl/revokedInt.pem")), + }, + { + desc: "Revoked leaf chain", + certs: makeChain(t, testdata.Path("crl/revokedLeaf.pem")), + }, + { + desc: "Chain with no CRL for issuer", + certs: makeChain(t, testdata.Path("client_cert_1.pem")), + expectNoCRL: true, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + for _, c := range tt.certs { + crl, err := p.CRL(c) + if err != nil { + t.Fatalf("Expected error fetch from provider: %v", err) + } + if crl == nil && !tt.expectNoCRL { + t.Fatalf("CRL is unexpectedly nil") + } + } + }) + } +} + +// TestFileWatcherCRLProviderConfig checks creation of FileWatcherCRLProvider, +// and the validation of FileWatcherOptions configuration. The configurations include empty +// one, non existing CRLDirectory, invalid RefreshDuration, and the correct one. +func (s) TestFileWatcherCRLProviderConfig(t *testing.T) { + if _, err := NewFileWatcherCRLProvider(FileWatcherOptions{}); err == nil { + t.Fatalf("Empty FileWatcherOptions should not be allowed") + } + if _, err := NewFileWatcherCRLProvider(FileWatcherOptions{CRLDirectory: "I_do_not_exist"}); err == nil { + t.Fatalf("CRLDirectory must exist") + } + defaultProvider, err := NewFileWatcherCRLProvider(FileWatcherOptions{CRLDirectory: testdata.Path("crl")}) + if err != nil { + t.Fatal("Unexpected error:", err) + } + if defaultProvider.opts.RefreshDuration != defaultCRLRefreshDuration { + t.Fatalf("RefreshDuration for defaultCRLRefreshDuration case is not properly updated by validate() func") + } + defaultProvider.Close() + tooFastRefreshProvider, err := NewFileWatcherCRLProvider(FileWatcherOptions{ + CRLDirectory: testdata.Path("crl"), + RefreshDuration: 5 * time.Second, + }) + if err != nil { + t.Fatal("Unexpected error:", err) + } + if tooFastRefreshProvider.opts.RefreshDuration != minCRLRefreshDuration { + t.Fatalf("RefreshDuration for minCRLRefreshDuration case is not properly updated by validate() func") + } + tooFastRefreshProvider.Close() + + customCallback := func(err error) { + fmt.Printf("Custom error message: %v", err) + } + regularProvider, err := NewFileWatcherCRLProvider(FileWatcherOptions{ + CRLDirectory: testdata.Path("crl"), + RefreshDuration: 2 * time.Hour, + CRLReloadingFailedCallback: customCallback, + }) + if err != nil { + t.Fatal("Unexpected error while creating regular FileWatcherCRLProvider:", err) + } + if regularProvider.opts.RefreshDuration != 2*time.Hour { + t.Fatalf("Valid refreshDuration was incorrectly updated by validate() func") + } + regularProvider.Close() +} + +// TestFileWatcherCRLProvider tests how FileWatcherCRLProvider handles the major +// four cases for CRL checks. It scans the CRLs under crl directory to populate +// the in-memory storage. Then we construct unrevoked, revoked leaf, and revoked +// intermediate chains, as well as a chain without CRL for issuer, and check +// that it’s correctly processed. Additionally, we also check if number of +// invocations of custom callback is correct. +func (s) TestFileWatcherCRLProvider(t *testing.T) { + const nonCRLFilesUnderCRLDirectory = 15 + nonCRLFilesSet := make(map[string]struct{}) + customCallback := func(err error) { + nonCRLFilesSet[err.Error()] = struct{}{} + } + p, err := NewFileWatcherCRLProvider(FileWatcherOptions{ + CRLDirectory: testdata.Path("crl"), + RefreshDuration: 1 * time.Hour, + CRLReloadingFailedCallback: customCallback, + }) + if err != nil { + t.Fatal("Unexpected error while creating FileWatcherCRLProvider:", err) + } + + // We need to make sure that initial CRLDirectory scan is completed before + // querying the internal map. + p.Close() + + // Each test data entry contains a description of a certificate chain, + // certificate chain itself, and if CRL is not expected to be found. + tests := []struct { + desc string + certs []*x509.Certificate + expectNoCRL bool + }{ + { + desc: "Unrevoked chain", + certs: makeChain(t, testdata.Path("crl/unrevoked.pem")), + }, + { + desc: "Revoked Intermediate chain", + certs: makeChain(t, testdata.Path("crl/revokedInt.pem")), + }, + { + desc: "Revoked leaf chain", + certs: makeChain(t, testdata.Path("crl/revokedLeaf.pem")), + }, + { + desc: "Chain with no CRL for issuer", + certs: makeChain(t, testdata.Path("client_cert_1.pem")), + expectNoCRL: true, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + for _, c := range tt.certs { + crl, err := p.CRL(c) + if err != nil { + t.Fatalf("Expected error fetch from provider: %v", err) + } + if crl == nil && !tt.expectNoCRL { + t.Fatalf("CRL is unexpectedly nil") + } + } + }) + } + if diff := cmp.Diff(len(nonCRLFilesSet), nonCRLFilesUnderCRLDirectory); diff != "" { + t.Errorf("Unexpected number Number of callback executions\ndiff (-got +want):\n%s", diff) + } +} + +// TestFileWatcherCRLProviderDirectoryScan tests how FileWatcherCRLProvider +// handles different contents of FileWatcherOptions.CRLDirectory. +// We update the content with various (correct and incorrect) CRL files and +// check if in-memory storage was properly updated. Please note that the same +// instance of FileWatcherCRLProvider is used for the whole test so test cases +// are not independent from each other. +func (s) TestFileWatcherCRLProviderDirectoryScan(t *testing.T) { + sourcePath := testdata.Path("crl") + targetPath := createTmpDir(t) + defer os.RemoveAll(targetPath) + p, err := NewFileWatcherCRLProvider(FileWatcherOptions{ + CRLDirectory: targetPath, + RefreshDuration: 1 * time.Hour, + }) + if err != nil { + t.Fatal("Unexpected error while creating FileWatcherCRLProvider:", err) + } + + // Each test data entry contains a description of CRL directory content + // (including the expected number of entries in the FileWatcherCRLProvider + // map), the name of the files to be copied there before executing the test + // case, and information regarding whether a specific certificate is expected + // to be found in the map. + tests := []struct { + desc string + crlFileNames []string + certFileNames []struct { + fileName string + expected bool + } + }{ + { + desc: "Simple addition (1 map entry)", + crlFileNames: []string{"1.crl"}, + certFileNames: []struct { + fileName string + expected bool + }{ + {"crl/unrevoked.pem", true}, + }, + }, + { + desc: "Addition and deletion (2 map entries)", + crlFileNames: []string{"3.crl", "5.crl"}, + certFileNames: []struct { + fileName string + expected bool + }{ + {"crl/revokedInt.pem", true}, + {"crl/revokedLeaf.pem", true}, + {"crl/unrevoked.pem", false}, + }, + }, + { + desc: "Addition and a corrupt file (3 map entries)", + crlFileNames: []string{"1.crl", "README.md"}, + certFileNames: []struct { + fileName string + expected bool + }{ + {"crl/revokedInt.pem", true}, + {"crl/revokedLeaf.pem", true}, + {"crl/unrevoked.pem", true}, + }}, + { + desc: "Full deletion (0 map entries)", + crlFileNames: []string{}, + certFileNames: []struct { + fileName string + expected bool + }{ + {"crl/revokedInt.pem", false}, + {"crl/revokedLeaf.pem", false}, + {"crl/unrevoked.pem", false}, + }}, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + copyFiles(sourcePath, targetPath, tt.crlFileNames, t) + p.scanCRLDirectory() + for _, certFileName := range tt.certFileNames { + c := makeChain(t, testdata.Path(certFileName.fileName))[0] + crl, err := p.CRL(c) + if err != nil { + t.Errorf("Cannot fetch CRL from provider: %v", err) + } + if crl == nil && certFileName.expected { + t.Errorf("CRL is unexpectedly nil") + } + if crl != nil && !certFileName.expected { + t.Errorf("CRL is unexpectedly not nil") + } + } + }) + } + p.Close() +} + +func copyFiles(sourcePath string, targetPath string, fileNames []string, t *testing.T) { + t.Helper() + targetDir, err := os.Open(targetPath) + if err != nil { + t.Fatalf("Can't open dir %v: %v", targetPath, err) + } + defer targetDir.Close() + names, err := targetDir.Readdirnames(-1) + if err != nil { + t.Fatalf("Can't read dir %v: %v", targetPath, err) + } + for _, name := range names { + err = os.RemoveAll(filepath.Join(testdata.Path(targetPath), name)) + if err != nil { + t.Fatalf("Can't remove file %v: %v", name, err) + } + } + for _, fileName := range fileNames { + destinationPath := filepath.Join(targetPath, fileName) + + sourceFile, err := os.Open(filepath.Join(sourcePath, fileName)) + if err != nil { + t.Fatalf("Can't open file %v: %v", fileName, err) + } + defer sourceFile.Close() + + destinationFile, err := os.Create(destinationPath) + if err != nil { + t.Fatalf("Can't create file %v: %v", destinationFile, err) + } + defer destinationFile.Close() + + _, err = io.Copy(destinationFile, sourceFile) + if err != nil { + t.Fatalf("Can't copy file %v to %v: %v", sourceFile, destinationFile, err) + } + } +} + +func createTmpDir(t *testing.T) string { + t.Helper() + + // Create a temp directory. Passing an empty string for the first argument + // uses the system temp directory. + dir, err := os.MkdirTemp("", "filewatcher*") + if err != nil { + t.Fatalf("os.MkdirTemp() failed: %v", err) + } + t.Logf("Using tmpdir: %s", dir) + return dir +} diff --git a/security/advancedtls/crl_test.go b/security/advancedtls/crl_test.go index 2821f2bd494d..b9ea2681484e 100644 --- a/security/advancedtls/crl_test.go +++ b/security/advancedtls/crl_test.go @@ -223,7 +223,7 @@ qsSIp8gfxSyzkJP+Ngkm2DdLjlJQCZ9R0MZP9Xj4 if err != nil { t.Fatalf("parseRevocationList(dummyCrlFile) failed: %v", err) } - crlExt := &certificateListExt{CertList: crl} + crlExt := &CRL{certList: crl} var crlIssuer pkix.Name = crl.Issuer var revocationTests = []struct { @@ -338,24 +338,12 @@ func makeChain(t *testing.T, name string) []*x509.Certificate { return certChain } -func loadCRL(t *testing.T, path string) *certificateListExt { - b, err := os.ReadFile(path) +func loadCRL(t *testing.T, path string) *CRL { + crl, err := ReadCRLFile(path) if err != nil { - t.Fatalf("readFile(%v) failed err = %v", path, err) + t.Fatalf("ReadCRLFile(%v) failed err = %v", path, err) } - crl, err := parseRevocationList(b) - if err != nil { - t.Fatalf("parseCrl(%v) failed err = %v", path, err) - } - crlExt, err := parseCRLExtensions(crl) - if err != nil { - t.Fatalf("parseCRLExtensions(%v) failed err = %v", path, err) - } - crlExt.RawIssuer, err = extractCRLIssuer(b) - if err != nil { - t.Fatalf("extractCRLIssuer(%v) failed err= %v", path, err) - } - return crlExt + return crl } func TestCachedCRL(t *testing.T) { @@ -371,16 +359,16 @@ func TestCachedCRL(t *testing.T) { }{ { desc: "Valid", - val: &certificateListExt{ - CertList: &x509.RevocationList{ + val: &CRL{ + certList: &x509.RevocationList{ NextUpdate: time.Now().Add(time.Hour), }}, ok: true, }, { desc: "Expired", - val: &certificateListExt{ - CertList: &x509.RevocationList{ + val: &CRL{ + certList: &x509.RevocationList{ NextUpdate: time.Now().Add(-time.Hour), }}, ok: false, @@ -455,11 +443,11 @@ func TestGetIssuerCRLCache(t *testing.T) { func TestVerifyCrl(t *testing.T) { tampered := loadCRL(t, testdata.Path("crl/1.crl")) // Change the signature so it won't verify - tampered.CertList.Signature[0]++ + tampered.certList.Signature[0]++ verifyTests := []struct { desc string - crl *certificateListExt + crl *CRL certs []*x509.Certificate cert *x509.Certificate errWant string @@ -521,6 +509,15 @@ func TestRevokedCert(t *testing.T) { revokedLeafChain := makeChain(t, testdata.Path("crl/revokedLeaf.pem")) validChain := makeChain(t, testdata.Path("crl/unrevoked.pem")) cache, err := lru.New(5) + rawCRLs := make([][]byte, 6) + for i := 1; i <= 6; i++ { + rawCRL, err := os.ReadFile(testdata.Path(fmt.Sprintf("crl/%d.crl", i))) + if err != nil { + t.Fatalf("readFile(%v) failed err = %v", fmt.Sprintf("crl/%d.crl", i), err) + } + rawCRLs = append(rawCRLs, rawCRL) + } + cRLProvider := NewStaticCRLProvider(rawCRLs) if err != nil { t.Fatalf("lru.New: err = %v", err) } @@ -579,7 +576,7 @@ func TestRevokedCert(t *testing.T) { } for _, tt := range revocationTests { - t.Run(tt.desc, func(t *testing.T) { + t.Run(fmt.Sprintf("%v with x509 crl hash dir", tt.desc), func(t *testing.T) { err := CheckRevocation(tt.in, RevocationConfig{ RootDir: testdata.Path("crl"), AllowUndetermined: tt.allowUndetermined, @@ -592,6 +589,18 @@ func TestRevokedCert(t *testing.T) { t.Error("Unrevoked certificate not allowed") } }) + t.Run(fmt.Sprintf("%v with static provider", tt.desc), func(t *testing.T) { + err := CheckRevocation(tt.in, RevocationConfig{ + AllowUndetermined: tt.allowUndetermined, + CRLProvider: cRLProvider, + }) + t.Logf("CheckRevocation err = %v", err) + if tt.revoked && err == nil { + t.Error("Revoked certificate chain was allowed") + } else if !tt.revoked && err != nil { + t.Error("Unrevoked certificate not allowed") + } + }) } } @@ -639,6 +648,7 @@ func setupTLSConn(t *testing.T) (net.Listener, *x509.Certificate, *ecdsa.Private } // TestVerifyConnection will setup a client/server connection and check revocation in the real TLS dialer +// TODO add CRL provider tests here? func TestVerifyConnection(t *testing.T) { lis, cert, key := setupTLSConn(t) defer func() { @@ -729,7 +739,7 @@ func TestIssuerNonPrintableString(t *testing.T) { if err != nil { t.Fatalf("failed to decode issuer: %s", err) } - _, err = fetchCRL(rawIssuer, RevocationConfig{RootDir: testdata.Path("crl")}) + _, err = fetchCRLOpenSSLHashDir(rawIssuer, RevocationConfig{RootDir: testdata.Path("crl")}) if err != nil { t.Fatalf("fetchCRL failed: %s", err) } @@ -756,8 +766,8 @@ func TestCRLCacheExpirationReloading(t *testing.T) { // `3.crl`` revokes `revokedInt.pem` crl := loadCRL(t, testdata.Path("crl/3.crl")) // Modify the crl so that the cert is NOT revoked and add it to the cache - crl.CertList.RevokedCertificates = nil - crl.CertList.NextUpdate = time.Now().Add(time.Hour) + crl.certList.RevokedCertificates = nil + crl.certList.NextUpdate = time.Now().Add(time.Hour) cache.Add(hex.EncodeToString(rawIssuer), crl) var cfg = RevocationConfig{RootDir: testdata.Path("crl"), Cache: cache} revocationStatus := checkChain(certs, cfg) @@ -766,7 +776,7 @@ func TestCRLCacheExpirationReloading(t *testing.T) { } // Modify the entry in the cache so that the cache will be refreshed - crl.CertList.NextUpdate = time.Now() + crl.certList.NextUpdate = time.Now() cache.Add(hex.EncodeToString(rawIssuer), crl) revocationStatus = checkChain(certs, cfg) diff --git a/security/advancedtls/go.mod b/security/advancedtls/go.mod index a055e4e82bf5..6617e795b793 100644 --- a/security/advancedtls/go.mod +++ b/security/advancedtls/go.mod @@ -3,6 +3,7 @@ module google.golang.org/grpc/security/advancedtls go 1.19 require ( + github.com/google/go-cmp v0.5.9 github.com/hashicorp/golang-lru v0.5.4 golang.org/x/crypto v0.14.0 google.golang.org/grpc v1.58.2 diff --git a/security/advancedtls/go.sum b/security/advancedtls/go.sum index f4f86746763d..de9e9ed173df 100644 --- a/security/advancedtls/go.sum +++ b/security/advancedtls/go.sum @@ -3,6 +3,7 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= diff --git a/security/advancedtls/internal/testutils/testutils.go b/security/advancedtls/internal/testutils/testutils.go index 1bc0dc3bf4e2..1ad272b4f846 100644 --- a/security/advancedtls/internal/testutils/testutils.go +++ b/security/advancedtls/internal/testutils/testutils.go @@ -35,12 +35,18 @@ type CertStore struct { // ClientCert2 is the certificate sent by client to prove its identity. // It is trusted by ServerTrust2. ClientCert2 tls.Certificate + // ClientCert3 is the certificate sent by client to prove its identity. + // It is trusted by ServerTrust3. Used in CRL tests + ClientCert3 tls.Certificate // ServerCert1 is the certificate sent by server to prove its identity. // It is trusted by ClientTrust1. ServerCert1 tls.Certificate // ServerCert2 is the certificate sent by server to prove its identity. // It is trusted by ClientTrust2. ServerCert2 tls.Certificate + // ServerCert3 is a revoked certificate + // (this info is stored in crl_server_revoked.pem). + ServerCert3 tls.Certificate // ServerPeer3 is the certificate sent by server to prove its identity. ServerPeer3 tls.Certificate // ServerPeerLocalhost1 is the certificate sent by server to prove its @@ -51,10 +57,14 @@ type CertStore struct { ClientTrust1 *x509.CertPool // ClientTrust2 is the root certificate used on the client side. ClientTrust2 *x509.CertPool + // ClientTrust3 is the root certificate used on the client side. + ClientTrust3 *x509.CertPool // ServerTrust1 is the root certificate used on the server side. ServerTrust1 *x509.CertPool // ServerTrust2 is the root certificate used on the server side. ServerTrust2 *x509.CertPool + // ServerTrust2 is the root certificate used on the server side. + ServerTrust3 *x509.CertPool } func readTrustCert(fileName string) (*x509.CertPool, error) { @@ -79,12 +89,18 @@ func (cs *CertStore) LoadCerts() error { if cs.ClientCert2, err = tls.LoadX509KeyPair(testdata.Path("client_cert_2.pem"), testdata.Path("client_key_2.pem")); err != nil { return err } + if cs.ClientCert3, err = tls.LoadX509KeyPair(testdata.Path("crl/provider_client_cert.pem"), testdata.Path("crl/provider_client_cert.key")); err != nil { + return err + } if cs.ServerCert1, err = tls.LoadX509KeyPair(testdata.Path("server_cert_1.pem"), testdata.Path("server_key_1.pem")); err != nil { return err } if cs.ServerCert2, err = tls.LoadX509KeyPair(testdata.Path("server_cert_2.pem"), testdata.Path("server_key_2.pem")); err != nil { return err } + if cs.ServerCert3, err = tls.LoadX509KeyPair(testdata.Path("crl/provider_server_cert.pem"), testdata.Path("crl/provider_server_cert.key")); err != nil { + return err + } if cs.ServerPeer3, err = tls.LoadX509KeyPair(testdata.Path("server_cert_3.pem"), testdata.Path("server_key_3.pem")); err != nil { return err } @@ -97,11 +113,17 @@ func (cs *CertStore) LoadCerts() error { if cs.ClientTrust2, err = readTrustCert(testdata.Path("client_trust_cert_2.pem")); err != nil { return err } + if cs.ClientTrust3, err = readTrustCert(testdata.Path("crl/provider_client_trust_cert.pem")); err != nil { + return err + } if cs.ServerTrust1, err = readTrustCert(testdata.Path("server_trust_cert_1.pem")); err != nil { return err } if cs.ServerTrust2, err = readTrustCert(testdata.Path("server_trust_cert_2.pem")); err != nil { return err } + if cs.ServerTrust3, err = readTrustCert(testdata.Path("crl/provider_server_trust_cert.pem")); err != nil { + return err + } return nil } diff --git a/security/advancedtls/testdata/crl/README.md b/security/advancedtls/testdata/crl/README.md index 00cb09c31928..33d5309f567e 100644 --- a/security/advancedtls/testdata/crl/README.md +++ b/security/advancedtls/testdata/crl/README.md @@ -46,3 +46,74 @@ Certificate chain where the leaf is revoked * Subject: C=US, ST=California, L=Mountain View, O=Google LLC, OU=Production, OU=campus-sln, CN=node CA (2021-02-02T07:32:57-08:00) * 6.crl + +## Test Data for testing CRL providers functionality + +To generate test data please follow the steps below or run provider_create.sh +script. All the files have `provider_` prefix. + +We need to generate the following artifacts for testing CRL provider: +* server self signed CA cert +* client self signed CA cert +* server cert signed by client CA +* client cert signed by server CA +* empty crl file +* crl file containing information about revoked server cert + +Please find the related commands below. + +* Generate self signed CAs +``` +$ openssl req -x509 -newkey rsa:4096 -keyout provider_server_trust_key.pem -out provider_server_trust_cert.pem -days 365 -subj "/C=US/ST=VA/O=Internet Widgits Pty Ltd/CN=foo.bar.hoo.ca.com" -nodes +$ openssl req -x509 -newkey rsa:4096 -keyout provider_client_trust_key.pem -out provider_client_trust_cert.pem -days 365 -subj "/C=US/ST=CA/L=SVL/O=Internet Widgits Pty Ltd" -nodes +``` + +* Generate client and server certs signed by CAs +``` +$ openssl req -newkey rsa:4096 -keyout provider_server_cert.key -out provider_new_cert.csr -nodes -subj "/C=US/ST=CA/L=DUMMYCITY/O=Internet Widgits Pty Ltd/CN=foo.bar.com" -sha256 +$ openssl x509 -req -in provider_new_cert.csr -out provider_server_cert.pem -CA provider_client_trust_cert.pem -CAkey provider_client_trust_key.pem -CAcreateserial -days 3650 -sha256 -extfile provider_extensions.conf + +$ openssl req -newkey rsa:4096 -keyout provider_client_cert.key -out provider_new_cert.csr -nodes -subj "/C=US/ST=CA/O=Internet Widgits Pty Ltd/CN=foo.bar.hoo.com" -sha256 +$ openssl x509 -req -in provider_new_cert.csr -out provider_client_cert.pem -CA provider_server_trust_cert.pem -CAkey provider_server_trust_key.pem -CAcreateserial -days 3650 -sha256 -extfile provider_extensions.conf +``` + +Here is the content of `provider_extensions.conf` - +``` +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment +``` + +* Generate CRLs + For CRL generation we need 2 more files called `index.txt` and `crlnumber.txt`: +``` +$ echo "1000" > provider_crlnumber.txt +$ touch provider_index.txt +``` +Also we need another config `provider_crl.cnf` - +``` +[ ca ] +default_ca = my_ca + +[ my_ca ] +crl = crl.pem +default_md = sha256 +database = provider_index.txt +crlnumber = provider_crlnumber.txt +default_crl_days = 30 +default_crl_hours = 1 +crl_extensions = crl_ext + +[crl_ext] +# Authority Key Identifier extension +authorityKeyIdentifier=keyid:always,issuer:always +``` + +The commands to generate empty CRL file and CRL file containing revoked server +cert are below. +``` +$ openssl ca -gencrl -keyfile provider_client_trust_key.pem -cert provider_client_trust_cert.pem -out provider_crl_empty.pem -config provider_crl.cnf +$ openssl ca -revoke provider_server_cert.pem -keyfile provider_client_trust_key.pem -cert provider_client_trust_cert.pem -config provider_crl.cnf +$ openssl ca -gencrl -keyfile provider_client_trust_key.pem -cert provider_client_trust_cert.pem -out provider_crl_server_revoked.pem -config provider_crl.cnf +``` \ No newline at end of file diff --git a/security/advancedtls/testdata/crl/provider_client_cert.key b/security/advancedtls/testdata/crl/provider_client_cert.key new file mode 100644 index 000000000000..b8b30bf5519c --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_client_cert.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +zDK1RAz8JZHyOJ4tVxpw76AxPUOv+A== +-----END PRIVATE KEY----- diff --git a/security/advancedtls/testdata/crl/provider_client_cert.pem b/security/advancedtls/testdata/crl/provider_client_cert.pem new file mode 100644 index 000000000000..50acd5a533b3 --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_client_cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFmTCCA4GgAwIBAgIUH+FcZgWO0XDKIU8T/mcyUE9YFhkwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZBMSEwHwYDVQQKDBhJbnRlcm5l +dCBXaWRnaXRzIFB0eSBMdGQxGzAZBgNVBAMMEmZvby5iYXIuaG9vLmNhLmNvbTAe +Fw0yMzEwMjAxODM1NTdaFw0zMzEwMTcxODM1NTdaMFcxCzAJBgNVBAYTAlVTMQsw +CQYDVQQIDAJDQTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRgw +FgYDVQQDDA9mb28uYmFyLmhvby5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDo9wlMibqqY/mTBdAquY+JORumIunnTXQMrMriB2/afgOJtoo1UABE +2evNabeh+qBlzVe7ouFBLG7fq0MtmiUP38kZRTJQhoXqI/boYgRbGAz5cE23OfJZ +9cvJMAAiVdLXNvmcmWf+CxPN0bKZNgZ0HYpqkalLO5hLUvCc225Kie/0CzuWcrA8 +GIxiMO/3VJj7vdWuiDbRPPGVBfEZEC7jCXUcLVyx17yvnxeODYjHwETVfVegSnHA +P4RY+H0HGwqu0ZBAWnbO9HC3q7o9CdW68KJYFP43c01AHO6vK1Kkkq3MkpP/uVx9 +DGOc+FPovUuui8s8pLQ6SIee2zq12YmQFdDFkwV/iFd6drCNBFWZF2EPRqldfebw +qur8eMAkP7KlnhFQ7C1R5xseW09rsBU4PVtGAuUfE0ATLPIMebiAlPU/1yr4oXFv +PT2qjS6dtgyoYifJSeN6/W2cpVhzmZs0WfJabHBOz+W59oq8Tl19xRb6vekwpbEl +mt2MVXSN1TvweQQPEqh/SjVr8QIp1nwZ1kZAiYAfLvBF9kqpjodg/ZIFpQiL9KmW +wv30IZX4Xv5LvLA/cgjPcGUDxvpyV6VCIbmS/dmqZP/JDE27GKRCG+tsugpaKsZW +8zOJbrBgYVNUM0hU02pXiqMMHGFP/FdYQlxXsiq5FYSxYEtuRNNNgQIDAQABo1ow +WDAdBgNVHQ4EFgQUQd4QRGICOG9KgbDjJTtEXfcdS2swHwYDVR0jBBgwFoAU0UZz +FCfHiQfVrExiD2QPevGA5VIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwDQYJKoZI +hvcNAQELBQADggIBAGqa4kbO3mnjuJy9PXvMCvF1BwFhv3ytRhrGU+h9HVbw9l1i +dZMTvS2NRVj4hyqCvtgxOrXKdbGBxcZEajzSJa+rSDmET9PGd7DdBlCLp0VXYgr0 +dQmtFPgwLCuTRYWqxixPMy1Hc2KWvljZ5K9fk8Rz+IL9Y3oqaClMz3yc7F5Ve2fd +dANKaIDdSVo9ScATMfineggfbz6L81dFamSzIBbvwfUX7Puop+Zq/g6sVz1vLg44 +FPK8Etw5LaLC+C7CX7+YD7bCs/v6p/Uv2N6AjP7W6h6zu3HlptytMNRjpcl30ur2 +j10AV4UuhlhZiwysvgJCHahcIaM+jVRXoWfDqnvrJjN1Pe4I7LkE4bNsumWl76An +V4/nRxXWQsXFhqOK3f/prKJzUJLr1Sfg4JafKFulb4HYqvNY16IQhqtSse+MyT0r +KwA+wqBREGosldOb8T9utgBxCmudPPXPlJjcER9WE1qzm5uHyeaNnewTZkF4xiCH +grrW3+ZVcjlLjqj5otGAnr1lMUA7K8bV1jJzB3o+QNCDL1y5uKeOGmLjP8xpQJQW +nPUQEmFa6YPWwWphE6LR5CURARQy9aRPILtPMommEc8KYXlBvYcRX1rGBVXjZNIE +Ibnt/7aJJ8BqwRBylhho1w7O14MZWDB6iR9xNW+4/pgaNYysS85WoF6z56UE +-----END CERTIFICATE----- diff --git a/security/advancedtls/testdata/crl/provider_client_trust_cert.pem b/security/advancedtls/testdata/crl/provider_client_trust_cert.pem new file mode 100644 index 000000000000..6c3f76dfa6b6 --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_client_trust_cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFdzCCA1+gAwIBAgIUKqY2Cg+WHLt9amXOOJBNlBXjEHkwDQYJKoZIhvcNAQEL +BQAwSzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxITAf +BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzEwMjAxODM1NTRa +Fw0yNDEwMTkxODM1NTRaMEsxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoG +A1UEBwwDU1ZMMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCt+gVYNPbMAsqrhziGDUFmM1aa +rxcKHlfu8DaKYYvs+KTguRRU69IozsdrXR6jzwCGiId926PuJ0FC0fuW52LC/2Xi +FW86MLwgJ0lP+C3WL5D4B6vLCVIaI2YWzLk+mfZ1PclsuvI2Ffq3UWXnZb9o7HIN +OgZ8TMISJGYDCtYHasNiWlYrQecrSf6KjRprT4+USXMDrUP3g0AEq9TYuxLXFZq3 +CMxC+6sV3KWOsNKbAVqQ8xZ/iTgLSzYfifi3ljXliIqj+9vz5Xtb4fxzzwEdqNPJ +tzbPCE+8wOdVg55Lagomb/EYO3wqS4eOzbZ5odX6IMEmsOEOk1+35V6IZtlPSIP2 +zk/JwtC4oZV8XexSu0aw+SSjKPosTQv5VGo1ptJhBxI7AVGWmaquX0C4JIsTIXn3 +HLqFVjdyYSX/fx2yfodmw2xIGfoCbEE3NQAjD/k4zZWhXeqA8qR3kcgwMsI+zsug +LHVC8hbRY5YdQFCH3mBwBsj5PLkcKevRRWSoIHd3m79nTFJClYtr3w6ublwFIndi +lsQysXHG5C49zMDOBJkISQ95dcIJwoQm22ePxjbhs2XCr/zFrtMtmkaD2uQBAt9a +uShY0aXiifkdoZ7fSjbQ7u+DzeaJ64g2RHSCyRbLDtp9L0eolN3q7u00Uc/vSzHW +8DeLGVtdqkmQIh04PQIDAQABo1MwUTAdBgNVHQ4EFgQULiFveRb8zO102dF5iXGd +xqir/4IwHwYDVR0jBBgwFoAULiFveRb8zO102dF5iXGdxqir/4IwDwYDVR0TAQH/ +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAQXb+u9cl2aVtchhW/qhwPjOU82BP +r1hByxiG95pQFdtquf953/jZ4S0GoDFE1lrfqcoaxSKWM6tTIUQxJmJxVDJaA1JI +eyc4qXceEZ/GZYAlP1BqGTsxqWNYVA1suKYMlpz2GZDGY1/M7Ggy56P1V5YeAgce +IGM65aj6eyc5SDtNqWperkpJdr960CkzoHreSbKzcWny7yF5W5L5WeZrovQj+FKI +tdcsajxRbxcTl/zqAVifRPIazfU+0g9pV5WvqF8p8HKFn3LgWZFkR4LfPXzepVy9 +/67R76vp48lmbUdMJ1llMHYHSvbjHwN7iT/MV7R1KUzpmjAJhcBg1GwrwT+hjcMW +bBfJYeAKXbekPWNUC0dpiAiaHR5znAjJ8zYtH9loFrZl5xlSIp8M8EFZiC9uecqL +REWrbjE6vZribAk5x6L2Qabr/7PBmhRPRMulC/Oc8TvBMa2YxjBZowEcXnYIIP0i +aLZ69Lrvle6axQT7ZYynSwrunRAlhVrDP8rAQH1UT1l3OV8GsZ0I3Mht0DEY/s83 +/siCVm3vteMUkv7WA7aKTB63MFjWg8lajbOlmgqLExoHRCAnBNY/NsHkFpm9xt0F +vIrQtU3GXk5Uyx/Vh0se81+0u74UQqZYJ/PbOLTDzRXolGq+zp++eiUMHvYnCXU7 +8vBcs8+CWNGSL20= +-----END CERTIFICATE----- diff --git a/security/advancedtls/testdata/crl/provider_client_trust_key.pem b/security/advancedtls/testdata/crl/provider_client_trust_key.pem new file mode 100644 index 000000000000..3d16b50a1f60 --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_client_trust_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +V5VXFg6RJMUHFm56NBP/NTCWFkBD2Dk= +-----END PRIVATE KEY----- diff --git a/security/advancedtls/testdata/crl/provider_create.sh b/security/advancedtls/testdata/crl/provider_create.sh new file mode 100755 index 000000000000..85189020dc9a --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_create.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# The script contains a sequence of commands described in README.md +openssl req -x509 \ + -newkey rsa:4096 \ + -keyout provider_server_trust_key.pem \ + -out provider_server_trust_cert.pem \ + -days 365 \ + -subj "/C=US/ST=VA/O=Internet Widgits Pty Ltd/CN=foo.bar.hoo.ca.com" \ + -nodes + +openssl req -x509 \ + -newkey rsa:4096 \ + -keyout provider_client_trust_key.pem \ + -out provider_client_trust_cert.pem \ + -days 365 \ + -subj "/C=US/ST=CA/L=SVL/O=Internet Widgits Pty Ltd" \ + -nodes + +openssl req -newkey rsa:4096 \ + -keyout provider_server_cert.key \ + -out provider_new_cert.csr \ + -nodes \ + -subj "/C=US/ST=CA/L=DUMMYCITY/O=Internet Widgits Pty Ltd/CN=foo.bar.com" \ + -sha256 + +openssl x509 -req \ + -in provider_new_cert.csr \ + -out provider_server_cert.pem \ + -CA provider_client_trust_cert.pem \ + -CAkey provider_client_trust_key.pem \ + -CAcreateserial \ + -days 3650 \ + -sha256 \ + -extfile provider_extensions.conf + +openssl req -newkey rsa:4096 \ + -keyout provider_client_cert.key \ + -out provider_new_cert.csr \ + -nodes \ + -subj "/C=US/ST=CA/O=Internet Widgits Pty Ltd/CN=foo.bar.hoo.com" \ + -sha256 + +openssl x509 -req \ + -in provider_new_cert.csr \ + -out provider_client_cert.pem \ + -CA provider_server_trust_cert.pem \ + -CAkey provider_server_trust_key.pem \ + -CAcreateserial \ + -days 3650 \ + -sha256 \ + -extfile provider_extensions.conf + +echo "1000" > provider_crlnumber.txt + +touch provider_index.txt + +openssl ca -gencrl \ + -keyfile provider_client_trust_key.pem \ + -cert provider_client_trust_cert.pem \ + -out provider_crl_empty.pem \ + -config provider_crl.cnf + +openssl ca -revoke provider_server_cert.pem \ + -keyfile provider_client_trust_key.pem \ + -cert provider_client_trust_cert.pem \ + -config provider_crl.cnf + +openssl ca -gencrl \ + -keyfile provider_client_trust_key.pem \ + -cert provider_client_trust_cert.pem \ + -out provider_crl_server_revoked.pem \ + -config provider_crl.cnf + + +rm *.csr diff --git a/security/advancedtls/testdata/crl/provider_crl.cnf b/security/advancedtls/testdata/crl/provider_crl.cnf new file mode 100644 index 000000000000..3f12ddfc2edb --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_crl.cnf @@ -0,0 +1,14 @@ +[ ca ] +default_ca = my_ca + +[ my_ca ] +default_md = sha256 +database = provider_index.txt +crlnumber = provider_crlnumber.txt +default_crl_days = 30 +default_crl_hours = 1 +crl_extensions = crl_ext + +[crl_ext] +# Authority Key Identifier extension +authorityKeyIdentifier=keyid:always,issuer:always diff --git a/security/advancedtls/testdata/crl/provider_crl_empty.pem b/security/advancedtls/testdata/crl/provider_crl_empty.pem new file mode 100644 index 000000000000..f9e7daae9b65 --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_crl_empty.pem @@ -0,0 +1,20 @@ +-----BEGIN X509 CRL----- +MIIDWjCCAUICAQEwDQYJKoZIhvcNAQELBQAwSzELMAkGA1UEBhMCVVMxCzAJBgNV +BAgMAkNBMQwwCgYDVQQHDANTVkwxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg +UHR5IEx0ZBcNMjMxMDIwMTgzNTU3WhcNMjMxMTE5MTkzNTU3WjAnMCUCFCBOb4be +aSBeU1CCmUkUOpLDLh4hFw0yMzEwMjAxODM0MTJaoIGZMIGWMIGGBgNVHSMEfzB9 +gBQuIW95FvzM7XTZ0XmJcZ3GqKv/gqFPpE0wSzELMAkGA1UEBhMCVVMxCzAJBgNV +BAgMAkNBMQwwCgYDVQQHDANTVkwxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg +UHR5IEx0ZIIUKqY2Cg+WHLt9amXOOJBNlBXjEHkwCwYDVR0UBAQCAhAAMA0GCSqG +SIb3DQEBCwUAA4ICAQCpo3SBHdRE+yCNw9dKcvIbDM01jPAYObxggP6YIuiS+ZgN +ozdDsoDBfzpo5gqR7tB4/PbD0TviJ25dWfWr9Kq2aobDrmDaemZ0tnURxiT+mI7e +327P9S1mrjSy07hlM0gX1CA9PmzrhCNiyS7w5EpHStTu768/ftMeostWJvRPBjIO +lVVEgibhxqxj7eWJ0xCMvwmp5oI3OXsjlkv2AvGvwrJI6EPbUKB8Ppa6LAEWaIfL +h0Uvd2U+FJCPdfHtQTTBarGdplS6cRxeR1EFfquHB78zoGE5ZH8sMUOclVAi3vJ7 +81PKce+dUIFhePTh4IKH+OcuMydSaVs6O9Ju8/DNTNMQvUkFqA/9doCDql3aaN+9 +bGjYEJLw5xWOfP8yF5qfppVahHWK4q9Ezm+vmALjcNMt/EcP6Gp7LhHUwnbE18+Y +krwJNG/RNnwDP0eNgeUQA+dGacEFnWX4RQ5lUIm1/DO1IBRHy5vali3qg/0Ryx/R +orafpcqLo6FUjZQz+W4URACzq37oRY4qMBr3yNzVpqaVpej8zluqEOZpf8gpo9EC +Cika7WeHaUk5U1FHAfzccIao+Xh/13nPQsEdR7VjsluNZHr/pOWZEigG0sBbIFxH +qfIZ4QaSnG0cr5XTkEYPu9W8SXD64Y9C1dyYtFFgsDyaBSSwOFvQfnbzZTOGEg== +-----END X509 CRL----- diff --git a/security/advancedtls/testdata/crl/provider_crl_server_revoked.pem b/security/advancedtls/testdata/crl/provider_crl_server_revoked.pem new file mode 100644 index 000000000000..c2ac42642d61 --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_crl_server_revoked.pem @@ -0,0 +1,21 @@ +-----BEGIN X509 CRL----- +MIIDgTCCAWkCAQEwDQYJKoZIhvcNAQELBQAwSzELMAkGA1UEBhMCVVMxCzAJBgNV +BAgMAkNBMQwwCgYDVQQHDANTVkwxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg +UHR5IEx0ZBcNMjMxMDIwMTgzNTU3WhcNMjMxMTE5MTkzNTU3WjBOMCUCFCBOb4be +aSBeU1CCmUkUOpLDLh4hFw0yMzEwMjAxODM0MTJaMCUCFCBOb4beaSBeU1CCmUkU +OpLDLh4iFw0yMzEwMjAxODM1NTdaoIGZMIGWMIGGBgNVHSMEfzB9gBQuIW95FvzM +7XTZ0XmJcZ3GqKv/gqFPpE0wSzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQww +CgYDVQQHDANTVkwxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIU +KqY2Cg+WHLt9amXOOJBNlBXjEHkwCwYDVR0UBAQCAhABMA0GCSqGSIb3DQEBCwUA +A4ICAQAylv3bjfdzUmWp8vVkIutABIwR4vrO54gVgslg0OUPC1C0iq/knpMywzT0 +xej4IRULVAhkNFE1mOjan37ghqPOvn+WGUlQD1VzCCnCc5aWoLSHNvIpfNe4Z0tU +VUrFMIiRBEAy3dznoTsBjwiXVjHx4MJ7w0cLDBfEsQgpmmdurFkpSSQFkfqG8+BU +Hqde1vdFld7iCwA0ooYTrb/BFUq2/JSz5pgxPZib/oYAxgP452cD6EBeteCMDx6L +WeKYTDqEzrB5fjYJRksNN+FW7nM7saHC4fSwXeAoR5N6uMF+KYMZxhz84G2ljz9T +Wt2e1fJ0hAOu3cxsMmkKRZjpNPmSUMxerylbkL7VXWgms5sohZ62L4GElnxSqVNC +a5Trtqpe6b5UrqIyr6MGzrrVafU/3C+gv5agCO+TuU+9kMv3/EzPn36fTMhtn8NF +PjgoA3DVqkOdTi3FaGBgAzixzeKX5RBkhyB9vlx5ojm3cKyk+CBoBhogadr8FClZ +/0ss98j0cIbWb93LS6et69LvWSoDNLMYKz8zZLqws6o6cIdPITOJbUjss8b3R7i2 +HfdElF7PJMJlW6L+1I8phhiQzCezCoBOdVD6YvdNmyxJj3m29bO3XrOdQf0Qj1QN +vYqyl+js5yNp6pEtwAxHfXqB6VZgmdG22kYHQFRaDdlU7VrzpA== +-----END X509 CRL----- diff --git a/security/advancedtls/testdata/crl/provider_extensions.conf b/security/advancedtls/testdata/crl/provider_extensions.conf new file mode 100644 index 000000000000..b414918a9e4b --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_extensions.conf @@ -0,0 +1,4 @@ +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment diff --git a/security/advancedtls/testdata/crl/provider_server_cert.key b/security/advancedtls/testdata/crl/provider_server_cert.key new file mode 100644 index 000000000000..52b559ee4f9c --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_server_cert.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +43iT2lxMrKbtvNlNluEqPbJ74GNB4T4c +-----END PRIVATE KEY----- diff --git a/security/advancedtls/testdata/crl/provider_server_cert.pem b/security/advancedtls/testdata/crl/provider_server_cert.pem new file mode 100644 index 000000000000..4e93f3de1f06 --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_server_cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFmjCCA4KgAwIBAgIUIE5vht5pIF5TUIKZSRQ6ksMuHiIwDQYJKoZIhvcNAQEL +BQAwSzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxITAf +BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzEwMjAxODM1NTVa +Fw0zMzEwMTcxODM1NTVaMGcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAG +A1UEBwwJRFVNTVlDSVRZMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM +dGQxFDASBgNVBAMMC2Zvby5iYXIuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAqn+0nu3KyN9vio3KTTz8E8ArmB0SrXTZWSIBmPlbNhDekUwtQxLU +05ukBnB3cYdbwjDb/X+5ikLx6OY5dyn02N6qW7YLCKycgi5fhsQS6RX851Pw8rXB +uQIaYcPcWAjBmtpRGxDNQuBuu/xZppEiziUT7AnobCJy0QvuMIC1E2yvL0xgT84z +TzBZap7UXwMcHCIhY6nWGAwVEZK4E+yI3xuSUUL+0AiX8e2xg9H5LQQgwP8Llx2S +aqIhlhl6BKAlGJMt9d8MokB1dDaiocxB/b9VTqME11OxAj5bZYXC71dcV3Am0XEG +rMA81YUfnKH0FONx6NQW0LR2YsxIWADRAtEflCpe7D3f3n0pjBzkDaFBt0KjEGCS +rr62bu8lzCjxXELr2yCMAWq8CnLlxmXNt9b9/SV242qWsA/cZJsXzgSzCEXVxp3a +VIl9noKdkIE2KgO4JcQo6viomGzcJ1LPeO4BlVWTavFu6vAcWjbgJZYpPYcoUKCA +juso1rdqMaEuvL7z2a5Sa+bFvQOVSNhbkuSFHORtWPEugfHsJyYm4C3Hyl94MaFJ +JEGfRLGDWGi1TjU9+SdGoIVBTq3dHhor5c8FzenbFiSAJ68aq4ehLqwlbGrKNKTb +vLSqwEKLsr6FVIllqsMMITmDmy05Klw99AbzovL/knrf+k2cACsx71sCAwEAAaNa +MFgwHQYDVR0OBBYEFF+qjGuxabV+x/NnfsDP50cFbBIrMB8GA1UdIwQYMBaAFC4h +b3kW/MztdNnReYlxncaoq/+CMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMA0GCSqG +SIb3DQEBCwUAA4ICAQBX4yzbJ4IewiGMTbSs2aH7x4WSRI7mrGBTwXBjdzQBaIn3 +vNMaKbxmt8BC36MVyGy6xoPOZJZiR2t6P6QjfpIiruIIw5cmqjw/7feyxxKNXIzR +BWXm0Nt/btkjgyHqPvtR7DcT+ko7tG94OJzeqW0ZiHaO9egufhEQjmwi5siKSh8Q +Df9vzNu9tgqlLyQiJZbKW9gmXMG33dIn5Dx9QF2ax+7UXuFqYs8Dwq9slmVkMRrX +2b0/7exS2ExOZpDWPZGc4+jr94MbF5O7sPSF/mDTh4nRGXJN/QBbw6maGtdv/5ov +lJ2z8lwdKiGO548xBX5IcyQrC+qgqo9pEewxWhfX7jfZQ121xkJYBqa/RDFo+f6Q +lJExnsqmLW82ZBkPzdiwW9xCdpirmTHwtizUQ8JlkV3jy9PSxRCaNrCrlhUISdNd +OjcGIlnjgz1bTJGJubsDpIkYUrv6w5WSY1RqYK1B8DnNyoPsHMWC5J0MxKpa/w3L +8VK5FoZthP+zJpT6IOZsGGMZ+X9nuqrpbI43lHMBIC30/fVJalrK/AOOfz9VULG7 +9ALv5OiP++If8+9wj4SOLhjpf+U5R+pH/g2oz3/ODGlJDV+ZX4FaxRUWeZwvGQv5 +aIH5v0zgFZIpyaIsdEm/zONqzqcIyLRMjixe7Xr/Q1vKPZXIVEj0DHvvjsl6+Q== +-----END CERTIFICATE----- diff --git a/security/advancedtls/testdata/crl/provider_server_trust_cert.pem b/security/advancedtls/testdata/crl/provider_server_trust_cert.pem new file mode 100644 index 000000000000..84b623b60dc4 --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_server_trust_cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFlTCCA32gAwIBAgIUBnhgsNLyVwPm+wWr9DCNqjHi/DYwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZBMSEwHwYDVQQKDBhJbnRlcm5l +dCBXaWRnaXRzIFB0eSBMdGQxGzAZBgNVBAMMEmZvby5iYXIuaG9vLmNhLmNvbTAe +Fw0yMzEwMjAxODM1NTBaFw0yNDEwMTkxODM1NTBaMFoxCzAJBgNVBAYTAlVTMQsw +CQYDVQQIDAJWQTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRsw +GQYDVQQDDBJmb28uYmFyLmhvby5jYS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCsY0i8YoKj4iwbTk7osHmBmOcfOF1NEVlTRj7Nx7PQ9dEowvnt +zE1392SbDPWDc4VbLBlvK2etBpOgUGMMQpaoMUuhVwe0KX+B0mvmOmmscpFqIml2 +5kRP6lF/ngCQD5W/NBPKyWR0FtghW0kBNU5DwPRTQH+h7LjWwegmOWi2DRwAiL08 +IMDA6akaqyJtCcuY6stWTSxm2yaW7ucXjm/FZBbiXoP4+Fa/Pgjq7kPLCCn/KdSg +av8Rt2ErfYnJUVe7KHt08ZD/z8gMD89RB2nJ/L2Xy7mylDC5yqIayPYiNtVbN/Fb +OaHsaBuVAbOOGV41mF0PrWdj7KQd9zZnIgtEfmK2OggeWCk6qo8qKEigxKI9eYxg +OvXOYevk8ozqqYUvwyhKPqpvFQvepD0w739pWowbKxwW+6xJhPd1yVSye2OLF7Fx +rzPlRXV7GuEDNwqrNbXMU6UdN8795iAIE8dr545S77RyKABiMvcvZBEI/j8ucEQI +as2LaKALfj/yYvaCL4y9CoA4239Q5embElamxKAvgT3CAj5+jcYHGx+IkJUv/1zl +n/ju51C/xfRk/iXf6UU2taODEtBKbC0xzJbnMyXFuYeS59IGo443C9148Rn8eRdF +Cg/hHapmlI3YVAjx61o3Kdgf5aDEj+0LHggfI7bIt2Fil/hmz56dX6sSvQIDAQAB +o1MwUTAdBgNVHQ4EFgQU0UZzFCfHiQfVrExiD2QPevGA5VIwHwYDVR0jBBgwFoAU +0UZzFCfHiQfVrExiD2QPevGA5VIwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAgEAALpRRiFhBU4ZcreZ3dDMThABAmQi8DAaxpTsLTGsGvvyWXtVPvXH +yWUjZEYYYv9IydBLJ4nACKZtLGm/X0+jBl9H9pYWZP35OYCoFnqAMXTdpmXby442 +F7/HWYBCt6z/9k2dN1Jb0ZoaA4uheBKOe+RP3sjv63il83F4hGXMToiTxQMRfaFj +aiQoXvs+06DozMEhB4d14+Bd18qdkJStFWWLUjsJ4TIpzWh4SKprMvePZoLjS/tZ +y7xatqwHsKoNvie0PjAolJpU+qcDlCp32UOkOYr8YDYojsYefQvb7qjUOfeUUocE +VI8mSLayEA8jF0ZIj4hPq4M1TVfUs168dEbsfnHy50H9yCCS+Qq4ubjiXW2M2U2Y +4XWAu0Kh1W/fxW5WVNwrahidmOc5oie4dAYOUcqZe8GnIG2hwBytUkPg9Vv/ImFw +jnJONDV2WekWAJfDSvRuVFi8RkxOyfCf7hhaGML6euwDwxWKxr/XjyZUSQud8l4a +PutvZB65SY4w8VawchPnZ/Hg9kbOtfauzJTyibiHBsiLZnihxrGK9JV8Nv5hg1es +gV9NIhbctR9N+faz631Dg9wZE3AJPEcuh3c2gYqG3UzbXgXk8xZXD/F6hYhTwqvs +W83vT5i+4qpTCnZZ9Zg7L9fo5KZb0DMTsdBUomH6oLJRKPu45l0rFOA= +-----END CERTIFICATE----- diff --git a/security/advancedtls/testdata/crl/provider_server_trust_key.pem b/security/advancedtls/testdata/crl/provider_server_trust_key.pem new file mode 100644 index 000000000000..4f4236cf0b03 --- /dev/null +++ b/security/advancedtls/testdata/crl/provider_server_trust_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +FhP/nZ3Y5l4y3XdzasT9ityH9SM= +-----END PRIVATE KEY-----