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  }