| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // Package certchecker contains implementation of CertChecker. | 5 // Package certchecker contains implementation of CertChecker. |
| 6 // | 6 // |
| 7 // CertChecker knows how to check certificate signatures and revocation status. | 7 // CertChecker knows how to check certificate signatures and revocation status. |
| 8 // | 8 // |
| 9 // Uses datastore entities managed by 'certconfig' package. | 9 // Uses datastore entities managed by 'certconfig' package. |
| 10 package certchecker | 10 package certchecker |
| 11 | 11 |
| 12 import ( | 12 import ( |
| 13 "crypto/x509" | 13 "crypto/x509" |
| 14 "fmt" | 14 "fmt" |
| 15 "time" | 15 "time" |
| 16 | 16 |
| 17 "golang.org/x/net/context" | 17 "golang.org/x/net/context" |
| 18 | 18 |
| 19 ds "github.com/luci/gae/service/datastore" | 19 ds "github.com/luci/gae/service/datastore" |
| 20 "github.com/luci/gae/service/info" | 20 "github.com/luci/gae/service/info" |
| 21 "github.com/luci/luci-go/common/clock" | 21 "github.com/luci/luci-go/common/clock" |
| 22 "github.com/luci/luci-go/common/data/caching/lazyslot" | 22 "github.com/luci/luci-go/common/data/caching/lazyslot" |
| 23 "github.com/luci/luci-go/common/data/caching/proccache" | 23 "github.com/luci/luci-go/common/data/caching/proccache" |
| 24 » "github.com/luci/luci-go/common/errors" | 24 » "github.com/luci/luci-go/common/retry" |
| 25 | 25 |
| 26 "github.com/luci/luci-go/tokenserver/appengine/impl/certconfig" | 26 "github.com/luci/luci-go/tokenserver/appengine/impl/certconfig" |
| 27 ) | 27 ) |
| 28 | 28 |
| 29 const ( | 29 const ( |
| 30 // RefetchCAPeriod is how often to check CA entity in the datastore. | 30 // RefetchCAPeriod is how often to check CA entity in the datastore. |
| 31 // | 31 // |
| 32 // A big value here is acceptable, since CA is changing only when servic
e | 32 // A big value here is acceptable, since CA is changing only when servic
e |
| 33 // config is changing (which happens infrequently). | 33 // config is changing (which happens infrequently). |
| 34 RefetchCAPeriod = 5 * time.Minute | 34 RefetchCAPeriod = 5 * time.Minute |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 // | 133 // |
| 134 // It caches CertChecker objects in local memory and reuses them between | 134 // It caches CertChecker objects in local memory and reuses them between |
| 135 // requests. | 135 // requests. |
| 136 func GetCertChecker(c context.Context, cn string) (*CertChecker, error) { | 136 func GetCertChecker(c context.Context, cn string) (*CertChecker, error) { |
| 137 checker, err := proccache.GetOrMake(c, proccacheKey(cn), func() (interfa
ce{}, time.Duration, error) { | 137 checker, err := proccache.GetOrMake(c, proccacheKey(cn), func() (interfa
ce{}, time.Duration, error) { |
| 138 // To avoid storing CertChecker for non-existent CAs in local me
mory forever, | 138 // To avoid storing CertChecker for non-existent CAs in local me
mory forever, |
| 139 // we do a datastore check when creating the checker. It happens
once during | 139 // we do a datastore check when creating the checker. It happens
once during |
| 140 // the process lifetime. | 140 // the process lifetime. |
| 141 switch exists, err := ds.Exists(c, ds.NewKey(c, "CA", cn, 0, nil
)); { | 141 switch exists, err := ds.Exists(c, ds.NewKey(c, "CA", cn, 0, nil
)); { |
| 142 case err != nil: | 142 case err != nil: |
| 143 » » » return nil, 0, errors.WrapTransient(err) | 143 » » » return nil, 0, retry.Tag.Apply(err) |
| 144 case !exists.All(): | 144 case !exists.All(): |
| 145 return nil, 0, Error{ | 145 return nil, 0, Error{ |
| 146 error: fmt.Errorf("no such CA %q", cn), | 146 error: fmt.Errorf("no such CA %q", cn), |
| 147 Reason: NoSuchCA, | 147 Reason: NoSuchCA, |
| 148 } | 148 } |
| 149 } | 149 } |
| 150 checker := &CertChecker{ | 150 checker := &CertChecker{ |
| 151 CN: cn, | 151 CN: cn, |
| 152 CRL: certconfig.NewCRLChecker(cn, certconfig.CRLShardCou
nt, refetchCRLPeriod(c)), | 152 CRL: certconfig.NewCRLChecker(cn, certconfig.CRLShardCou
nt, refetchCRLPeriod(c)), |
| 153 } | 153 } |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 // certconfig.CA struct (that will be cached in ch.ca as usual). It acts as an | 276 // certconfig.CA struct (that will be cached in ch.ca as usual). It acts as an |
| 277 // indicator to GetCA to return NoSuchCA error, since returning a error here | 277 // indicator to GetCA to return NoSuchCA error, since returning a error here |
| 278 // would just cause a retry of 'refetchCA' later, and returning (nil, nil) is | 278 // would just cause a retry of 'refetchCA' later, and returning (nil, nil) is |
| 279 // forbidden (per lazyslot.Slot API). | 279 // forbidden (per lazyslot.Slot API). |
| 280 func (ch *CertChecker) refetchCA(c context.Context) (*certconfig.CA, error) { | 280 func (ch *CertChecker) refetchCA(c context.Context) (*certconfig.CA, error) { |
| 281 ca := &certconfig.CA{CN: ch.CN} | 281 ca := &certconfig.CA{CN: ch.CN} |
| 282 switch err := ds.Get(c, ca); { | 282 switch err := ds.Get(c, ca); { |
| 283 case err == ds.ErrNoSuchEntity: | 283 case err == ds.ErrNoSuchEntity: |
| 284 return &certconfig.CA{}, nil // GetCA knows that empty struct me
ans "no such CA" | 284 return &certconfig.CA{}, nil // GetCA knows that empty struct me
ans "no such CA" |
| 285 case err != nil: | 285 case err != nil: |
| 286 » » return nil, errors.WrapTransient(err) | 286 » » return nil, retry.Tag.Apply(err) |
| 287 } | 287 } |
| 288 | 288 |
| 289 parsedConf, err := ca.ParseConfig() | 289 parsedConf, err := ca.ParseConfig() |
| 290 if err != nil { | 290 if err != nil { |
| 291 return nil, fmt.Errorf("can't parse stored config for %q - %s",
ca.CN, err) | 291 return nil, fmt.Errorf("can't parse stored config for %q - %s",
ca.CN, err) |
| 292 } | 292 } |
| 293 ca.ParsedConfig = parsedConf | 293 ca.ParsedConfig = parsedConf |
| 294 | 294 |
| 295 parsedCert, err := x509.ParseCertificate(ca.Cert) | 295 parsedCert, err := x509.ParseCertificate(ca.Cert) |
| 296 if err != nil { | 296 if err != nil { |
| 297 return nil, fmt.Errorf("can't parse stored cert for %q - %s", ca
.CN, err) | 297 return nil, fmt.Errorf("can't parse stored cert for %q - %s", ca
.CN, err) |
| 298 } | 298 } |
| 299 ca.ParsedCert = parsedCert | 299 ca.ParsedCert = parsedCert |
| 300 | 300 |
| 301 return ca, nil | 301 return ca, nil |
| 302 } | 302 } |
| OLD | NEW |