1 //go:generate stringer -type=FeatureFlag 2 3 package features 4 5 import ( 6 "fmt" 7 "strings" 8 "sync" 9 ) 10 11 type FeatureFlag int 12 13 const ( 14 unused FeatureFlag = iota // unused is used for testing 15 // Deprecated features, these can be removed once stripped from production configs 16 StoreRevokerInfo 17 ROCSPStage6 18 ROCSPStage7 19 StoreLintingCertificateInsteadOfPrecertificate 20 CAAValidationMethods 21 CAAAccountURI 22 LeaseCRLShards 23 24 // Currently in-use features 25 // EnforceMultiVA causes the VA to block on remote VA PerformValidation 26 // requests in order to make a valid/invalid decision with the results. 27 EnforceMultiVA 28 // MultiVAFullResults will cause the main VA to wait for all of the remote VA 29 // results, not just the threshold required to make a decision. 30 MultiVAFullResults 31 // ECDSAForAll enables all accounts, regardless of their presence in the CA's 32 // ecdsaAllowedAccounts config value, to get issuance from ECDSA issuers. 33 ECDSAForAll 34 // ServeRenewalInfo exposes the renewalInfo endpoint in the directory and for 35 // GET requests. WARNING: This feature is a draft and highly unstable. 36 ServeRenewalInfo 37 // AllowUnrecognizedFeatures is internal to the features package: if true, 38 // skip error when unrecognized feature flag names are passed. 39 AllowUnrecognizedFeatures 40 41 // ExpirationMailerUsesJoin enables using a JOIN query in expiration-mailer 42 // rather than a SELECT from certificateStatus followed by thousands of 43 // one-row SELECTs from certificates. 44 ExpirationMailerUsesJoin 45 46 // CertCheckerChecksValidations enables an extra query for each certificate 47 // checked, to find the relevant authzs. Since this query might be 48 // expensive, we gate it behind a feature flag. 49 CertCheckerChecksValidations 50 51 // CertCheckerRequiresValidations causes cert-checker to fail if the 52 // query enabled by CertCheckerChecksValidations didn't find corresponding 53 // authorizations. 54 CertCheckerRequiresValidations 55 56 // CertCheckerRequiresCorrespondence enables an extra query for each certificate 57 // checked, to find the linting precertificate in the `precertificates` table. 58 // It then checks that the final certificate "corresponds" to the precertificate 59 // using `precert.Correspond`. 60 CertCheckerRequiresCorrespondence 61 62 // AsyncFinalize enables the RA to return approximately immediately from 63 // requests to finalize orders. This allows us to take longer getting SCTs, 64 // issuing certs, and updating the database; it indirectly reduces the number 65 // of issuances that fail due to timeouts during storage. However, it also 66 // requires clients to properly implement polling the Order object to wait 67 // for the cert URL to appear. 68 AsyncFinalize 69 70 // RequireCommonName defaults to true, and causes the CA to fail to issue a 71 // certificate if there is no CommonName in the certificate. When false, the 72 // CA will be willing to issue certificates with no CN. 73 // 74 // According to the BRs Section 7.1.4.2.2(a), the commonName field is 75 // Deprecated, and its inclusion is discouraged but not (yet) prohibited. 76 RequireCommonName 77 78 // CAAAfterValidation causes the VA to only kick off CAA checks after the base 79 // domain control validation has completed and succeeded. This makes 80 // successful validations slower by serializing the DCV and CAA work, but 81 // makes unsuccessful validations easier by not doing CAA work at all. 82 CAAAfterValidation 83 ) 84 85 // List of features and their default value, protected by fMu 86 var features = map[FeatureFlag]bool{ 87 unused: false, 88 CAAValidationMethods: false, 89 CAAAccountURI: false, 90 EnforceMultiVA: false, 91 MultiVAFullResults: false, 92 StoreRevokerInfo: false, 93 ECDSAForAll: false, 94 ServeRenewalInfo: false, 95 AllowUnrecognizedFeatures: false, 96 ROCSPStage6: false, 97 ROCSPStage7: false, 98 ExpirationMailerUsesJoin: false, 99 CertCheckerChecksValidations: false, 100 CertCheckerRequiresValidations: false, 101 CertCheckerRequiresCorrespondence: false, 102 AsyncFinalize: false, 103 RequireCommonName: true, 104 LeaseCRLShards: false, 105 CAAAfterValidation: false, 106 107 StoreLintingCertificateInsteadOfPrecertificate: false, 108 } 109 110 var fMu = new(sync.RWMutex) 111 112 var initial = map[FeatureFlag]bool{} 113 114 var nameToFeature = make(map[string]FeatureFlag, len(features)) 115 116 func init() { 117 for f, v := range features { 118 nameToFeature[f.String()] = f 119 initial[f] = v 120 } 121 } 122 123 // Set accepts a list of features and whether they should 124 // be enabled or disabled. In the presence of unrecognized 125 // flags, it will return an error or not depending on the 126 // value of AllowUnrecognizedFeatures. 127 func Set(featureSet map[string]bool) error { 128 fMu.Lock() 129 defer fMu.Unlock() 130 var unknown []string 131 for n, v := range featureSet { 132 f, present := nameToFeature[n] 133 if present { 134 features[f] = v 135 } else { 136 unknown = append(unknown, n) 137 } 138 } 139 if len(unknown) > 0 && !features[AllowUnrecognizedFeatures] { 140 return fmt.Errorf("unrecognized feature flag names: %s", 141 strings.Join(unknown, ", ")) 142 } 143 return nil 144 } 145 146 // Enabled returns true if the feature is enabled or false 147 // if it isn't, it will panic if passed a feature that it 148 // doesn't know. 149 func Enabled(n FeatureFlag) bool { 150 fMu.RLock() 151 defer fMu.RUnlock() 152 v, present := features[n] 153 if !present { 154 panic(fmt.Sprintf("feature '%s' doesn't exist", n.String())) 155 } 156 return v 157 } 158 159 // Reset resets the features to their initial state 160 func Reset() { 161 fMu.Lock() 162 defer fMu.Unlock() 163 for k, v := range initial { 164 features[k] = v 165 } 166 } 167