k8s.io/kubernetes@v1.29.3/pkg/controller/certificates/authority/policies.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package authority 18 19 import ( 20 "crypto/x509" 21 "fmt" 22 "sort" 23 "time" 24 25 capi "k8s.io/api/certificates/v1" 26 ) 27 28 // SigningPolicy validates a CertificateRequest before it's signed by the 29 // CertificateAuthority. It may default or otherwise mutate a certificate 30 // template. 31 type SigningPolicy interface { 32 // not-exporting apply forces signing policy implementations to be internal 33 // to this package. 34 apply(template *x509.Certificate, signerNotAfter time.Time) error 35 } 36 37 // PermissiveSigningPolicy is the signing policy historically used by the local 38 // signer. 39 // 40 // - It forwards all SANs from the original signing request. 41 // - It sets allowed usages as configured in the policy. 42 // - It zeros all extensions. 43 // - It sets BasicConstraints to true. 44 // - It sets IsCA to false. 45 // - It validates that the signer has not expired. 46 // - It sets NotBefore and NotAfter: 47 // All certificates set NotBefore = Now() - Backdate. 48 // Long-lived certificates set NotAfter = Now() + TTL - Backdate. 49 // Short-lived certificates set NotAfter = Now() + TTL. 50 // All certificates truncate NotAfter to the expiration date of the signer. 51 type PermissiveSigningPolicy struct { 52 // TTL is used in certificate NotAfter calculation as described above. 53 TTL time.Duration 54 55 // Usages are the allowed usages of a certificate. 56 Usages []capi.KeyUsage 57 58 // Backdate is used in certificate NotBefore calculation as described above. 59 Backdate time.Duration 60 61 // Short is the duration used to determine if the lifetime of a certificate should be considered short. 62 Short time.Duration 63 64 // Now defaults to time.Now but can be stubbed for testing 65 Now func() time.Time 66 } 67 68 func (p PermissiveSigningPolicy) apply(tmpl *x509.Certificate, signerNotAfter time.Time) error { 69 var now time.Time 70 if p.Now != nil { 71 now = p.Now() 72 } else { 73 now = time.Now() 74 } 75 76 ttl := p.TTL 77 78 usage, extUsages, err := keyUsagesFromStrings(p.Usages) 79 if err != nil { 80 return err 81 } 82 tmpl.KeyUsage = usage 83 tmpl.ExtKeyUsage = extUsages 84 85 tmpl.ExtraExtensions = nil 86 tmpl.Extensions = nil 87 tmpl.BasicConstraintsValid = true 88 tmpl.IsCA = false 89 90 tmpl.NotBefore = now.Add(-p.Backdate) 91 92 if ttl < p.Short { 93 // do not backdate the end time if we consider this to be a short lived certificate 94 tmpl.NotAfter = now.Add(ttl) 95 } else { 96 tmpl.NotAfter = now.Add(ttl - p.Backdate) 97 } 98 99 if !tmpl.NotAfter.Before(signerNotAfter) { 100 tmpl.NotAfter = signerNotAfter 101 } 102 103 if !tmpl.NotBefore.Before(signerNotAfter) { 104 return fmt.Errorf("the signer has expired: NotAfter=%v", signerNotAfter) 105 } 106 107 if !now.Before(signerNotAfter) { 108 return fmt.Errorf("refusing to sign a certificate that expired in the past: NotAfter=%v", signerNotAfter) 109 } 110 111 return nil 112 } 113 114 var keyUsageDict = map[capi.KeyUsage]x509.KeyUsage{ 115 capi.UsageSigning: x509.KeyUsageDigitalSignature, 116 capi.UsageDigitalSignature: x509.KeyUsageDigitalSignature, 117 capi.UsageContentCommitment: x509.KeyUsageContentCommitment, 118 capi.UsageKeyEncipherment: x509.KeyUsageKeyEncipherment, 119 capi.UsageKeyAgreement: x509.KeyUsageKeyAgreement, 120 capi.UsageDataEncipherment: x509.KeyUsageDataEncipherment, 121 capi.UsageCertSign: x509.KeyUsageCertSign, 122 capi.UsageCRLSign: x509.KeyUsageCRLSign, 123 capi.UsageEncipherOnly: x509.KeyUsageEncipherOnly, 124 capi.UsageDecipherOnly: x509.KeyUsageDecipherOnly, 125 } 126 127 var extKeyUsageDict = map[capi.KeyUsage]x509.ExtKeyUsage{ 128 capi.UsageAny: x509.ExtKeyUsageAny, 129 capi.UsageServerAuth: x509.ExtKeyUsageServerAuth, 130 capi.UsageClientAuth: x509.ExtKeyUsageClientAuth, 131 capi.UsageCodeSigning: x509.ExtKeyUsageCodeSigning, 132 capi.UsageEmailProtection: x509.ExtKeyUsageEmailProtection, 133 capi.UsageSMIME: x509.ExtKeyUsageEmailProtection, 134 capi.UsageIPsecEndSystem: x509.ExtKeyUsageIPSECEndSystem, 135 capi.UsageIPsecTunnel: x509.ExtKeyUsageIPSECTunnel, 136 capi.UsageIPsecUser: x509.ExtKeyUsageIPSECUser, 137 capi.UsageTimestamping: x509.ExtKeyUsageTimeStamping, 138 capi.UsageOCSPSigning: x509.ExtKeyUsageOCSPSigning, 139 capi.UsageMicrosoftSGC: x509.ExtKeyUsageMicrosoftServerGatedCrypto, 140 capi.UsageNetscapeSGC: x509.ExtKeyUsageNetscapeServerGatedCrypto, 141 } 142 143 // keyUsagesFromStrings will translate a slice of usage strings from the 144 // certificates API ("pkg/apis/certificates".KeyUsage) to x509.KeyUsage and 145 // x509.ExtKeyUsage types. 146 func keyUsagesFromStrings(usages []capi.KeyUsage) (x509.KeyUsage, []x509.ExtKeyUsage, error) { 147 var keyUsage x509.KeyUsage 148 var unrecognized []capi.KeyUsage 149 extKeyUsages := make(map[x509.ExtKeyUsage]struct{}) 150 for _, usage := range usages { 151 if val, ok := keyUsageDict[usage]; ok { 152 keyUsage |= val 153 } else if val, ok := extKeyUsageDict[usage]; ok { 154 extKeyUsages[val] = struct{}{} 155 } else { 156 unrecognized = append(unrecognized, usage) 157 } 158 } 159 160 var sorted sortedExtKeyUsage 161 for eku := range extKeyUsages { 162 sorted = append(sorted, eku) 163 } 164 sort.Sort(sorted) 165 166 if len(unrecognized) > 0 { 167 return 0, nil, fmt.Errorf("unrecognized usage values: %q", unrecognized) 168 } 169 170 return keyUsage, sorted, nil 171 } 172 173 type sortedExtKeyUsage []x509.ExtKeyUsage 174 175 func (s sortedExtKeyUsage) Len() int { 176 return len(s) 177 } 178 179 func (s sortedExtKeyUsage) Swap(i, j int) { 180 s[i], s[j] = s[j], s[i] 181 } 182 183 func (s sortedExtKeyUsage) Less(i, j int) bool { 184 return s[i] < s[j] 185 }