github.com/Venafi/vcert/v5@v5.10.2/pkg/certificate/extKeyUsage.go (about) 1 /* 2 * Copyright 2022 Venafi, Inc. 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 certificate 18 19 import ( 20 "crypto/x509" 21 "crypto/x509/pkix" 22 "encoding/asn1" 23 "fmt" 24 "strings" 25 26 "github.com/Venafi/vcert/v5/pkg/verror" 27 "gopkg.in/yaml.v3" 28 ) 29 30 /* 31 type ExtKeyUsage struct { 32 id x509.ExtKeyUsage 33 oid asn1.ObjectIdentifier 34 name string 35 } 36 */ 37 // ExtKeyUsage represents an extended set of actions that are valid for a given key. 38 // Each of the ExtKeyUsage* constants define a unique action. 39 type ExtKeyUsage x509.ExtKeyUsage 40 41 const ( 42 strUnknownExtKeyUsage = "UnknownExtKeyUsage" 43 strExtKeyUsageAny = "Any" 44 strExtKeyUsageServerAuth = "ServerAuth" 45 strExtKeyUsageClientAuth = "ClientAuth" 46 strExtKeyUsageCodeSigning = "CodeSigning" 47 strExtKeyUsageEmailProtection = "EmailProtection" 48 strExtKeyUsageIPSECEndSystem = "IPSECEndSystem" 49 strExtKeyUsageIPSECTunnel = "IPSECTunnel" 50 strExtKeyUsageIPSECUser = "IPSECUser" 51 strExtKeyUsageTimeStamping = "TimeStamping" 52 strExtKeyUsageOCSPSigning = "OCSPSigning" 53 strExtKeyUsageMicrosoftServerGatedCrypto = "MicrosoftServerGatedCrypto" 54 strExtKeyUsageNetscapeServerGatedCrypto = "NetscapeServerGatedCrypto" 55 strExtKeyUsageMicrosoftCommercialCodeSigning = "MicrosoftCommercialCodeSigning" 56 strExtKeyUsageMicrosoftKernelCodeSigning = "MicrosoftKernelCodeSigning" 57 58 // Unknown ExtKeyUsage. WARNING: crypto/x509.ExtKeyUsage does not declare an undefined 59 // ExtKeyUsage constant! 60 UnknownExtKeyUsage ExtKeyUsage = -1 61 // ExtKeyUsageAny represents an EKU of Any (oid: 2.5.29.37.0) 62 ExtKeyUsageAny = ExtKeyUsage(x509.ExtKeyUsageAny) 63 // ExtKeyUsageServerAuth represents an EKU of ServerAuth (oid: 1.3.6.1.5.5.7.3.1) 64 ExtKeyUsageServerAuth = ExtKeyUsage(x509.ExtKeyUsageServerAuth) 65 // ExtKeyUsageClientAuth represents an EKU of ClientAuth (oid: 1.3.6.1.5.5.7.3.2) 66 ExtKeyUsageClientAuth = ExtKeyUsage(x509.ExtKeyUsageClientAuth) 67 // ExtKeyUsageCodeSigning represents an EKU of CodeSigning (oid: 1.3.6.1.5.5.7.3.3) 68 ExtKeyUsageCodeSigning = ExtKeyUsage(x509.ExtKeyUsageCodeSigning) 69 // ExtKeyUsageEmailProtection represents an EKU of EmailProtection (oid: 1.3.6.1.5.5.7.3.4) 70 ExtKeyUsageEmailProtection = ExtKeyUsage(x509.ExtKeyUsageEmailProtection) 71 // ExtKeyUsageIPSECEndSystem represents an EKU of IPSECEndSystem (oid: 1.3.6.1.5.5.7.3.5) 72 ExtKeyUsageIPSECEndSystem = ExtKeyUsage(x509.ExtKeyUsageIPSECEndSystem) 73 // ExtKeyUsageIPSECTunnel represents an EKU of IPSECTunnel (oid: 1.3.6.1.5.5.7.3.6) 74 ExtKeyUsageIPSECTunnel = ExtKeyUsage(x509.ExtKeyUsageIPSECTunnel) 75 // ExtKeyUsageIPSECUser represents an EKU of IPSECUser (oid: 1.3.6.1.5.5.7.3.7) 76 ExtKeyUsageIPSECUser = ExtKeyUsage(x509.ExtKeyUsageIPSECUser) 77 // ExtKeyUsageTimeStamping represents an EKU of TimeStamping (oid: 1.3.6.1.5.5.7.3.8) 78 ExtKeyUsageTimeStamping = ExtKeyUsage(x509.ExtKeyUsageTimeStamping) 79 // ExtKeyUsageOCSPSigning represents an EKU of OCSPSigning (oid: 1.3.6.1.5.5.7.3.9) 80 ExtKeyUsageOCSPSigning = ExtKeyUsage(x509.ExtKeyUsageOCSPSigning) 81 // ExtKeyUsageMicrosoftServerGatedCrypto represents an EKU of MicrosoftServerGatedCrypto (oid: 1.3.6.1.4.1.311.10.3.3) 82 ExtKeyUsageMicrosoftServerGatedCrypto = ExtKeyUsage(x509.ExtKeyUsageMicrosoftServerGatedCrypto) 83 // ExtKeyUsageNetscapeServerGatedCrypto represents an EKU of NetscapeServerGatedCrypto (oid: 2.16.840.1.113730.4.1) 84 ExtKeyUsageNetscapeServerGatedCrypto = ExtKeyUsage(x509.ExtKeyUsageNetscapeServerGatedCrypto) 85 // ExtKeyUsageMicrosoftCommercialCodeSigning represents an EKU of MicrosoftCommercialCodeSigning (oid: 1.3.6.1.4.1.311.2.1.22) 86 ExtKeyUsageMicrosoftCommercialCodeSigning = ExtKeyUsage(x509.ExtKeyUsageMicrosoftCommercialCodeSigning) 87 // ExtKeyUsageMicrosoftKernelCodeSigning represents an EKU of MicrosoftKernelCodeSigning (oid: 1.3.6.1.4.1.311.61.1.1) 88 ExtKeyUsageMicrosoftKernelCodeSigning = ExtKeyUsage(x509.ExtKeyUsageMicrosoftKernelCodeSigning) 89 ) 90 91 var ( 92 // The ASN1 Object Identifier for the X509 extension Extended Key Usage. In ASN1 93 // the specifiec Extended Key Usage OIDs are elements sequenced under this OID. 94 ExtensionExtKeyUsageOid = asn1.ObjectIdentifier{2, 5, 29, 37} 95 96 // The ASN1 Object Identifier for Extended Key Usage: Any 97 ExtKeyUsageAnyOid = asn1.ObjectIdentifier{2, 5, 29, 37, 0} 98 // The ASN1 Object Identifier for Extended Key Usage: ServerAuth 99 ExtKeyUsageServerAuthOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} 100 // The ASN1 Object Identifier for Extended Key Usage: ClientAuth 101 ExtKeyUsageClientAuthOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} 102 // The ASN1 Object Identifier for Extended Key Usage: CodeSigning 103 ExtKeyUsageCodeSigningOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} 104 // The ASN1 Object Identifier for Extended Key Usage: EmailProtection 105 ExtKeyUsageEmailProtectionOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} 106 // The ASN1 Object Identifier for Extended Key Usage: IPSECEndSystem 107 ExtKeyUsageIPSECEndSystemOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} 108 // The ASN1 Object Identifier for Extended Key Usage: IPSECTunnel 109 ExtKeyUsageIPSECTunnelOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} 110 // The ASN1 Object Identifier for Extended Key Usage: IPSECUser 111 ExtKeyUsageIPSECUserOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} 112 // The ASN1 Object Identifier for Extended Key Usage: TimeStamping 113 ExtKeyUsageTimeStampingOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} 114 // The ASN1 Object Identifier for Extended Key Usage: OCSPSigning 115 ExtKeyUsageOCSPSigningOid = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} 116 // The ASN1 Object Identifier for Extended Key Usage: MicrosoftServerGatedCrypto 117 ExtKeyUsageMicrosoftServerGatedCryptoOid = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} 118 // The ASN1 Object Identifier for Extended Key Usage: MicrosoftCommercialCodeSigning 119 ExtKeyUsageMicrosoftCommercialCodeSigningOid = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22} 120 // The ASN1 Object Identifier for Extended Key Usage: MicrosoftKernelCodeSigning 121 ExtKeyUsageMicrosoftKernelCodeSigningOid = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1} 122 // The ASN1 Object Identifier for Extended Key Usage: NetscapeServerGatedCrypto 123 ExtKeyUsageNetscapeServerGatedCryptoOid = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} 124 ) 125 126 // Returns the string representation of this object 127 func (eku *ExtKeyUsage) String() string { 128 switch *eku { 129 case ExtKeyUsageAny: 130 return strExtKeyUsageAny 131 case ExtKeyUsageServerAuth: 132 return strExtKeyUsageServerAuth 133 case ExtKeyUsageClientAuth: 134 return strExtKeyUsageClientAuth 135 case ExtKeyUsageCodeSigning: 136 return strExtKeyUsageCodeSigning 137 case ExtKeyUsageEmailProtection: 138 return strExtKeyUsageEmailProtection 139 case ExtKeyUsageIPSECEndSystem: 140 return strExtKeyUsageIPSECEndSystem 141 case ExtKeyUsageIPSECTunnel: 142 return strExtKeyUsageIPSECTunnel 143 case ExtKeyUsageIPSECUser: 144 return strExtKeyUsageIPSECUser 145 case ExtKeyUsageTimeStamping: 146 return strExtKeyUsageTimeStamping 147 case ExtKeyUsageOCSPSigning: 148 return strExtKeyUsageOCSPSigning 149 case ExtKeyUsageMicrosoftServerGatedCrypto: 150 return strExtKeyUsageMicrosoftServerGatedCrypto 151 case ExtKeyUsageNetscapeServerGatedCrypto: 152 return strExtKeyUsageNetscapeServerGatedCrypto 153 case ExtKeyUsageMicrosoftCommercialCodeSigning: 154 return strExtKeyUsageMicrosoftCommercialCodeSigning 155 case ExtKeyUsageMicrosoftKernelCodeSigning: 156 return strExtKeyUsageMicrosoftKernelCodeSigning 157 default: 158 return strUnknownExtKeyUsage 159 } 160 } 161 162 // Returns the ASN1 Obect Indentifier represented by the ExtKeyUsage type 163 func (eku *ExtKeyUsage) Oid() (asn1.ObjectIdentifier, error) { 164 switch *eku { 165 case ExtKeyUsageAny: 166 return ExtKeyUsageAnyOid, nil 167 case ExtKeyUsageServerAuth: 168 return ExtKeyUsageServerAuthOid, nil 169 case ExtKeyUsageClientAuth: 170 return ExtKeyUsageClientAuthOid, nil 171 case ExtKeyUsageCodeSigning: 172 return ExtKeyUsageCodeSigningOid, nil 173 case ExtKeyUsageEmailProtection: 174 return ExtKeyUsageEmailProtectionOid, nil 175 case ExtKeyUsageIPSECEndSystem: 176 return ExtKeyUsageIPSECEndSystemOid, nil 177 case ExtKeyUsageIPSECTunnel: 178 return ExtKeyUsageIPSECTunnelOid, nil 179 case ExtKeyUsageIPSECUser: 180 return ExtKeyUsageIPSECUserOid, nil 181 case ExtKeyUsageTimeStamping: 182 return ExtKeyUsageTimeStampingOid, nil 183 case ExtKeyUsageOCSPSigning: 184 return ExtKeyUsageOCSPSigningOid, nil 185 case ExtKeyUsageMicrosoftServerGatedCrypto: 186 return ExtKeyUsageMicrosoftServerGatedCryptoOid, nil 187 case ExtKeyUsageNetscapeServerGatedCrypto: 188 return ExtKeyUsageNetscapeServerGatedCryptoOid, nil 189 case ExtKeyUsageMicrosoftCommercialCodeSigning: 190 return ExtKeyUsageMicrosoftCommercialCodeSigningOid, nil 191 case ExtKeyUsageMicrosoftKernelCodeSigning: 192 return ExtKeyUsageMicrosoftKernelCodeSigningOid, nil 193 default: 194 return nil, fmt.Errorf("%w: %s", verror.VcertError, strUnknownExtKeyUsage) 195 } 196 } 197 198 // X509Type() returns the crypto/x509.ExtKeyUsage type 199 func (eku *ExtKeyUsage) X509Type() x509.ExtKeyUsage { 200 // This is essentially a cast to ExtKeyUsage type, since ExtKeyUsage is 201 // an extension of crypt/x509.ExtKeyUsage 202 return x509.ExtKeyUsage(*eku) 203 } 204 205 // Sets the ExtKeyUsage type via a string. Sets the object to UnknownExtKeyUsage if not 206 // one of the defined Extended Key Usage strings 207 func (eku *ExtKeyUsage) set(s string) { 208 switch strings.ToUpper(s) { 209 case strings.ToUpper(strExtKeyUsageAny): 210 *eku = ExtKeyUsageAny 211 return 212 case strings.ToUpper(strExtKeyUsageServerAuth): 213 *eku = ExtKeyUsageServerAuth 214 return 215 case strings.ToUpper(strExtKeyUsageClientAuth): 216 *eku = ExtKeyUsageClientAuth 217 return 218 case strings.ToUpper(strExtKeyUsageCodeSigning): 219 *eku = ExtKeyUsageCodeSigning 220 return 221 case strings.ToUpper(strExtKeyUsageEmailProtection): 222 *eku = ExtKeyUsageEmailProtection 223 return 224 case strings.ToUpper(strExtKeyUsageIPSECEndSystem): 225 *eku = ExtKeyUsageIPSECEndSystem 226 return 227 case strings.ToUpper(strExtKeyUsageIPSECTunnel): 228 *eku = ExtKeyUsageIPSECTunnel 229 return 230 case strings.ToUpper(strExtKeyUsageIPSECUser): 231 *eku = ExtKeyUsageIPSECUser 232 return 233 case strings.ToUpper(strExtKeyUsageTimeStamping): 234 *eku = ExtKeyUsageTimeStamping 235 return 236 case strings.ToUpper(strExtKeyUsageOCSPSigning): 237 *eku = ExtKeyUsageOCSPSigning 238 return 239 case strings.ToUpper(strExtKeyUsageMicrosoftServerGatedCrypto): 240 *eku = ExtKeyUsageMicrosoftServerGatedCrypto 241 return 242 case strings.ToUpper(strExtKeyUsageNetscapeServerGatedCrypto): 243 *eku = ExtKeyUsageNetscapeServerGatedCrypto 244 return 245 case strings.ToUpper(strExtKeyUsageMicrosoftCommercialCodeSigning): 246 *eku = ExtKeyUsageMicrosoftCommercialCodeSigning 247 return 248 case strings.ToUpper(strExtKeyUsageMicrosoftKernelCodeSigning): 249 *eku = ExtKeyUsageMicrosoftKernelCodeSigning 250 return 251 default: 252 *eku = UnknownExtKeyUsage 253 return 254 } 255 } 256 257 func ParseExtKeyUsage(s string) (ExtKeyUsage, error) { 258 eku := *new(ExtKeyUsage) 259 eku.set(s) 260 if eku == UnknownExtKeyUsage { 261 return eku, fmt.Errorf("%w: %s \"%s\"", verror.VcertError, strUnknownExtKeyUsage, s) 262 } 263 return eku, nil 264 } 265 266 func addExtKeyUsage(req *x509.CertificateRequest, ekus []ExtKeyUsage) error { 267 var oidToAdd []asn1.ObjectIdentifier 268 for _, eku := range ekus { 269 oid, _ := eku.Oid() 270 if oid != nil { 271 oidToAdd = append(oidToAdd, oid) 272 } 273 } 274 275 if oidToAdd == nil && len(oidToAdd) < 1 { 276 // There was nothing to add (unknown or empty ekus) 277 return nil 278 } 279 280 bValue, err := asn1.Marshal(oidToAdd) 281 if err != nil { 282 return err 283 } 284 285 updatedExts := []pkix.Extension{ 286 { 287 Id: ExtensionExtKeyUsageOid, 288 Critical: false, 289 Value: bValue, 290 }, 291 } 292 293 // Preserve any other extra extensions, if any 294 for _, ext := range req.ExtraExtensions { 295 if !ext.Id.Equal(ExtensionExtKeyUsageOid) { 296 updatedExts = append(updatedExts, ext) 297 } 298 } 299 req.ExtraExtensions = updatedExts 300 return nil 301 } 302 303 // MarshalYAML customizes the behavior of ExtKeyUsage when being marshaled into a YAML document. 304 // The returned value is marshaled in place of the original value implementing Marshaller 305 func (eku *ExtKeyUsage) MarshalYAML() (interface{}, error) { 306 return eku.String(), nil 307 } 308 309 // UnmarshalYAML customizes the behavior when being unmarshalled from a YAML document 310 func (eku *ExtKeyUsage) UnmarshalYAML(value *yaml.Node) error { 311 var strValue string 312 err := value.Decode(&strValue) 313 if err != nil { 314 return err 315 } 316 317 *eku, err = ParseExtKeyUsage(strValue) 318 if err != nil { 319 return err 320 } 321 return nil 322 } 323 324 // A slice that contains multiple ExtKeyUsage types, with useful functions for 325 // adding and parsing the slice 326 type ExtKeyUsageSlice []ExtKeyUsage 327 328 func NewExtKeyUsageSlice(param any) *ExtKeyUsageSlice { 329 switch v := param.(type) { 330 case ExtKeyUsageSlice: 331 // This is essentially a copy 332 t := make([]ExtKeyUsage, len(v)) 333 _ = copy(t, []ExtKeyUsage(v)) 334 ret := ExtKeyUsageSlice(t) 335 return &ret 336 default: 337 ret := new(ExtKeyUsageSlice) 338 _ = ret.Add(param) 339 return ret 340 } 341 } 342 343 func (es *ExtKeyUsageSlice) String() string { 344 var ret string 345 for _, s := range *es { 346 ret += fmt.Sprintf("%s\n", s.String()) 347 } 348 return ret 349 } 350 351 func (es *ExtKeyUsageSlice) Exists(eku ExtKeyUsage) bool { 352 for _, el := range *es { 353 if el == eku { 354 return true 355 } 356 } 357 return false 358 } 359 360 func (es *ExtKeyUsageSlice) Add(param any) error { 361 switch v := param.(type) { 362 case ExtKeyUsage: 363 return es.appendByEKU(v) 364 case string: 365 return es.appendByString(v) 366 case []string: 367 var errs []string 368 for _, s := range v { 369 err := es.appendByString(s) 370 if err != nil { 371 errs = append(errs, s) 372 } 373 } 374 if errs != nil { 375 return fmt.Errorf("invalid EKUs: %s", strings.Join(errs, "; ")) 376 } 377 return nil 378 default: 379 return fmt.Errorf("cannot add from unknown type passed to Add function") 380 } 381 } 382 383 func (es *ExtKeyUsageSlice) appendByString(value string) error { 384 temp, _ := ParseExtKeyUsage(value) 385 err := es.appendByEKU(temp) 386 if err != nil { 387 return err 388 } 389 return nil 390 } 391 392 func (es *ExtKeyUsageSlice) appendByEKU(eku ExtKeyUsage) error { 393 if eku != UnknownExtKeyUsage { 394 if !es.Exists(eku) { 395 *es = append(*es, eku) 396 } 397 return nil 398 } 399 return fmt.Errorf("invalid EKU: %s", eku.String()) 400 }