github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/cache.go (about) 1 // Copyright (C) MongoDB, Inc. 2017-present. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7 package ocsp 8 9 import ( 10 "crypto" 11 "sync" 12 "time" 13 14 "golang.org/x/crypto/ocsp" 15 ) 16 17 type cacheKey struct { 18 HashAlgorithm crypto.Hash 19 IssuerNameHash string 20 IssuerKeyHash string 21 SerialNumber string 22 } 23 24 // Cache represents an OCSP cache. 25 type Cache interface { 26 Update(*ocsp.Request, *ResponseDetails) *ResponseDetails 27 Get(request *ocsp.Request) *ResponseDetails 28 } 29 30 // ConcurrentCache is an implementation of ocsp.Cache that's safe for concurrent use. 31 type ConcurrentCache struct { 32 cache map[cacheKey]*ResponseDetails 33 sync.Mutex 34 } 35 36 var _ Cache = (*ConcurrentCache)(nil) 37 38 // NewCache creates an empty OCSP cache. 39 func NewCache() *ConcurrentCache { 40 return &ConcurrentCache{ 41 cache: make(map[cacheKey]*ResponseDetails), 42 } 43 } 44 45 // Update updates the cache entry for the provided request. The provided response will only be cached if it has a 46 // status that is not ocsp.Unknown and has a non-zero NextUpdate time. If there is an existing cache entry for request, 47 // it will be overwritten by response if response.NextUpdate is further ahead in the future than the existing entry's 48 // NextUpdate. 49 // 50 // This function returns the most up-to-date response corresponding to the request. 51 func (c *ConcurrentCache) Update(request *ocsp.Request, response *ResponseDetails) *ResponseDetails { 52 unknown := response.Status == ocsp.Unknown 53 hasUpdateTime := !response.NextUpdate.IsZero() 54 canBeCached := !unknown && hasUpdateTime 55 key := createCacheKey(request) 56 57 c.Lock() 58 defer c.Unlock() 59 60 current, ok := c.cache[key] 61 if !ok { 62 if canBeCached { 63 c.cache[key] = response 64 } 65 66 // Return the provided response even though it might not have been cached because it's the most up-to-date 67 // response available. 68 return response 69 } 70 71 // If the new response is Unknown, we can't cache it. Return the existing cached response. 72 if unknown { 73 return current 74 } 75 76 // If a response has no nextUpdate set, the responder is telling us that newer information is always available. 77 // In this case, remove the existing cache entry because it is stale and return the new response because it is 78 // more up-to-date. 79 if !hasUpdateTime { 80 delete(c.cache, key) 81 return response 82 } 83 84 // If we get here, the new response is conclusive and has a non-empty nextUpdate so it can be cached. Overwrite 85 // the existing cache entry if the new one will be valid for longer. 86 newest := current 87 if response.NextUpdate.After(current.NextUpdate) { 88 c.cache[key] = response 89 newest = response 90 } 91 return newest 92 } 93 94 // Get returns the cached response for the request, or nil if there is no cached response. If the cached response has 95 // expired, it will be removed from the cache and nil will be returned. 96 func (c *ConcurrentCache) Get(request *ocsp.Request) *ResponseDetails { 97 key := createCacheKey(request) 98 99 c.Lock() 100 defer c.Unlock() 101 102 response, ok := c.cache[key] 103 if !ok { 104 return nil 105 } 106 107 if time.Now().UTC().Before(response.NextUpdate) { 108 return response 109 } 110 delete(c.cache, key) 111 return nil 112 } 113 114 func createCacheKey(request *ocsp.Request) cacheKey { 115 return cacheKey{ 116 HashAlgorithm: request.HashAlgorithm, 117 IssuerNameHash: string(request.IssuerNameHash), 118 IssuerKeyHash: string(request.IssuerKeyHash), 119 SerialNumber: request.SerialNumber.String(), 120 } 121 }