github.com/vmware/govmomi@v0.51.0/cli/extension/setcert.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package extension
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"crypto/rand"
    11  	"crypto/rsa"
    12  	"crypto/x509"
    13  	"crypto/x509/pkix"
    14  	"encoding/pem"
    15  	"flag"
    16  	"fmt"
    17  	"io"
    18  	"math/big"
    19  	"os"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/vmware/govmomi/cli"
    24  	"github.com/vmware/govmomi/cli/flags"
    25  	"github.com/vmware/govmomi/object"
    26  )
    27  
    28  type setcert struct {
    29  	*flags.ClientFlag
    30  
    31  	cert string
    32  	org  string
    33  
    34  	encodedCert bytes.Buffer
    35  }
    36  
    37  func init() {
    38  	cli.Register("extension.setcert", &setcert{})
    39  }
    40  
    41  func (cmd *setcert) Register(ctx context.Context, f *flag.FlagSet) {
    42  	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
    43  	cmd.ClientFlag.Register(ctx, f)
    44  
    45  	f.StringVar(&cmd.cert, "cert-pem", "-", "PEM encoded certificate")
    46  	f.StringVar(&cmd.org, "org", "VMware", "Organization for generated certificate")
    47  }
    48  
    49  func (cmd *setcert) Process(ctx context.Context) error {
    50  	if err := cmd.ClientFlag.Process(ctx); err != nil {
    51  		return err
    52  	}
    53  	return nil
    54  }
    55  
    56  func (cmd *setcert) Usage() string {
    57  	return "ID"
    58  }
    59  
    60  func (cmd *setcert) Description() string {
    61  	return `Set certificate for the extension ID.
    62  
    63  The '-cert-pem' option can be one of the following:
    64  '-' : Read the certificate from stdin
    65  '+' : Generate a new key pair and save locally to ID.crt and ID.key
    66  ... : Any other value is passed as-is to ExtensionManager.SetCertificate
    67  
    68  Examples:
    69    govc extension.setcert -cert-pem + -org Example com.example.extname`
    70  }
    71  
    72  func (cmd *setcert) create(id string) error {
    73  	certFile, err := os.Create(id + ".crt")
    74  	if err != nil {
    75  		return err
    76  	}
    77  	defer certFile.Close()
    78  
    79  	keyFile, err := os.Create(id + ".key")
    80  	if err != nil {
    81  		return err
    82  	}
    83  	defer keyFile.Close()
    84  
    85  	priv, err := rsa.GenerateKey(rand.Reader, 2048)
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	notBefore := time.Now()
    91  	notAfter := notBefore.Add(5 * 365 * 24 * time.Hour) // 5 years
    92  
    93  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    94  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	template := x509.Certificate{
   100  		SerialNumber: serialNumber,
   101  		Subject: pkix.Name{
   102  			Organization: []string{cmd.org},
   103  		},
   104  		NotBefore:             notBefore,
   105  		NotAfter:              notAfter,
   106  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   107  		BasicConstraintsValid: true,
   108  	}
   109  
   110  	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	err = pem.Encode(&cmd.encodedCert, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	_, err = certFile.Write(cmd.encodedCert.Bytes())
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	err = pem.Encode(keyFile, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	return nil
   131  }
   132  
   133  func (cmd *setcert) Run(ctx context.Context, f *flag.FlagSet) error {
   134  	if f.NArg() != 1 {
   135  		return flag.ErrHelp
   136  	}
   137  
   138  	key := f.Arg(0)
   139  
   140  	if cmd.cert == "-" {
   141  		b, err := io.ReadAll(os.Stdin)
   142  		if err != nil {
   143  			return err
   144  		}
   145  		cmd.cert = string(b)
   146  	} else if strings.HasPrefix(cmd.cert, "+") {
   147  		if err := cmd.create(key); err != nil {
   148  			return fmt.Errorf("creating certificate: %s", err)
   149  		}
   150  		if cmd.cert == "++" {
   151  			return nil // just generate a cert, useful for testing
   152  		}
   153  		cmd.cert = cmd.encodedCert.String()
   154  	}
   155  
   156  	c, err := cmd.Client()
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	m, err := object.GetExtensionManager(c)
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	return m.SetCertificate(ctx, key, cmd.cert)
   167  }