go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/cmd/selfsigned-cert/main.go (about)

     1  // Copyright 2023 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Executable selfsigned-cert generates a self-signed TLS certificate.
    16  //
    17  // Largely based on https://go.dev/src/crypto/tls/generate_cert.go
    18  package main
    19  
    20  import (
    21  	"crypto/rand"
    22  	"crypto/rsa"
    23  	"crypto/x509"
    24  	"crypto/x509/pkix"
    25  	"encoding/pem"
    26  	"flag"
    27  	"log"
    28  	"math/big"
    29  	"os"
    30  	"path/filepath"
    31  	"time"
    32  )
    33  
    34  var (
    35  	hostname = flag.String("hostname", "", "Server hostname (will be used as Subject CN), default to OS hostname")
    36  	duration = flag.Duration("duration", 5*365*24*time.Hour, "Duration that certificate is valid for")
    37  	rsaBits  = flag.Int("rsa-bits", 4096, "Size of RSA key to generate")
    38  	keyOut   = flag.String("key-out", "key.pem", "Where to store the private key")
    39  	certOut  = flag.String("cert-out", "cert.pem", "Where to store the certificate")
    40  )
    41  
    42  func main() {
    43  	flag.Parse()
    44  	if *hostname == "" {
    45  		var err error
    46  		if *hostname, err = os.Hostname(); err != nil {
    47  			log.Fatalf("Failed to get hostname: %s", err)
    48  		}
    49  	}
    50  
    51  	log.Printf("Generating %d bit RSA key", *rsaBits)
    52  	priv, err := rsa.GenerateKey(rand.Reader, *rsaBits)
    53  	if err != nil {
    54  		log.Fatalf("Failed to generate RSA key: %s", err)
    55  	}
    56  	privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
    57  	if err != nil {
    58  		log.Fatalf("Unable to marshal private key: %s", err)
    59  	}
    60  
    61  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    62  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
    63  	if err != nil {
    64  		log.Fatalf("Failed to generate serial number: %s", err)
    65  	}
    66  
    67  	log.Printf("Generating certificate for %q, SN %s", *hostname, serialNumber)
    68  	template := x509.Certificate{
    69  		SerialNumber:          serialNumber,
    70  		Subject:               pkix.Name{CommonName: *hostname},
    71  		DNSNames:              []string{*hostname},
    72  		NotBefore:             time.Now().Add(-time.Hour),
    73  		NotAfter:              time.Now().Add(*duration),
    74  		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
    75  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    76  		BasicConstraintsValid: true,
    77  	}
    78  	certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
    79  	if err != nil {
    80  		log.Fatalf("Failed to create certificate: %s", err)
    81  	}
    82  
    83  	writePEM(*certOut, "CERTIFICATE", certBytes)
    84  	writePEM(*keyOut, "PRIVATE KEY", privBytes)
    85  }
    86  
    87  func writePEM(path, typ string, bytes []byte) {
    88  	log.Printf("Writing %s", path)
    89  	if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
    90  		log.Fatalf("Failed to create path to %s: %s", path, err)
    91  	}
    92  	f, err := os.Create(path)
    93  	if err != nil {
    94  		log.Fatalf("Failed to open %s: %s", path, err)
    95  	}
    96  	if err := pem.Encode(f, &pem.Block{Type: typ, Bytes: bytes}); err != nil {
    97  		log.Fatalf("Failed to write data to %s: %s", path, err)
    98  	}
    99  	if err := f.Close(); err != nil {
   100  		log.Fatalf("Error closing %s: %s", path, err)
   101  	}
   102  }