github.com/google/martian/v3@v3.3.3/h2/testing/certs.go (about)

     1  // Copyright 2021 Google Inc. All rights reserved.
     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  package testing
    16  
    17  import (
    18  	"crypto"
    19  	"crypto/rand"
    20  	"crypto/rsa"
    21  	"crypto/sha256"
    22  	"crypto/tls"
    23  	"crypto/x509"
    24  	"crypto/x509/pkix"
    25  	"fmt"
    26  	"log"
    27  	"os"
    28  	"time"
    29  
    30  	"github.com/google/martian/v3/cybervillains"
    31  	"github.com/google/martian/v3/mitm"
    32  	"google.golang.org/grpc/credentials"
    33  )
    34  
    35  var (
    36  	// CA is the certificate authority. It uses the Cybervillains key pair.
    37  	CA *x509.Certificate
    38  	// CAKey is the private key of the certificate authority.
    39  	CAKey crypto.PrivateKey
    40  
    41  	// RootCAs is a certificate pool containing `CA`.
    42  	RootCAs *x509.CertPool
    43  
    44  	// ClientTLS is a set of transport credentials to use with chains signed by `CA`.
    45  	ClientTLS credentials.TransportCredentials
    46  
    47  	// Localhost is a certificate for "localhost" signed by `CA`.
    48  	Localhost *tls.Certificate
    49  )
    50  
    51  func init() {
    52  	var err error
    53  	CA, CAKey, err = initCA()
    54  	if err != nil {
    55  		log.Fatalf("Error initializing Cybervillains CA: %v", err)
    56  	}
    57  
    58  	RootCAs = x509.NewCertPool()
    59  	RootCAs.AddCert(CA)
    60  	ClientTLS = credentials.NewClientTLSFromCert(RootCAs, "")
    61  
    62  	Localhost, err = initLocalhostCert(CA, CAKey)
    63  	if err != nil {
    64  		log.Fatalf("Error creating localhost server certificate: %v", err)
    65  	}
    66  }
    67  
    68  func initCA() (*x509.Certificate, crypto.PrivateKey, error) {
    69  	chain, err := tls.X509KeyPair([]byte(cybervillains.Cert), []byte(cybervillains.Key))
    70  	if err != nil {
    71  		return nil, nil, fmt.Errorf("creating Cybervillains root: %w", err)
    72  	}
    73  	cert, err := x509.ParseCertificate(chain.Certificate[0])
    74  	if err != nil {
    75  		return nil, nil, fmt.Errorf("parsing Cybervillains certificate: %w", err)
    76  	}
    77  	return cert, chain.PrivateKey, nil
    78  }
    79  
    80  func initLocalhostCert(ca *x509.Certificate, caPriv crypto.PrivateKey) (*tls.Certificate, error) {
    81  	priv, err := rsa.GenerateKey(rand.Reader, 2048)
    82  	if err != nil {
    83  		return nil, fmt.Errorf("generating random key: %w", err)
    84  	}
    85  
    86  	// Subject Key Identifier support for end entity certificate.
    87  	// https://www.ietf.org/rfc/rfc3280.txt (section 4.2.1.2)
    88  	pkixpub, err := x509.MarshalPKIXPublicKey(priv.Public())
    89  	if err != nil {
    90  		return nil, fmt.Errorf("marshalling public key: %w", err)
    91  	}
    92  	hasher := sha256.New()
    93  	hasher.Write(pkixpub)
    94  	keyID := hasher.Sum(nil)
    95  
    96  	serial, err := rand.Int(rand.Reader, mitm.MaxSerialNumber)
    97  	if err != nil {
    98  		return nil, fmt.Errorf("generating serial number: %w", err)
    99  	}
   100  
   101  	hostname, err := os.Hostname()
   102  	if err != nil {
   103  		return nil, fmt.Errorf("getting hostname for creating cert: %w", err)
   104  	}
   105  
   106  	tmpl := &x509.Certificate{
   107  		SerialNumber: serial,
   108  		Subject: pkix.Name{
   109  			CommonName:   hostname,
   110  			Organization: []string{"Martian Proxy"},
   111  		},
   112  		SubjectKeyId:          keyID,
   113  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   114  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   115  		BasicConstraintsValid: true,
   116  		NotBefore:             time.Now().Add(-time.Hour),
   117  		NotAfter:              time.Now().Add(time.Hour),
   118  		DNSNames:              []string{hostname},
   119  	}
   120  
   121  	der, err := x509.CreateCertificate(rand.Reader, tmpl, ca, priv.Public(), caPriv)
   122  	if err != nil {
   123  		return nil, fmt.Errorf("creating X509 server certificate: %w", err)
   124  	}
   125  	x509c, err := x509.ParseCertificate(der)
   126  	if err != nil {
   127  		return nil, fmt.Errorf("parsing DER encoded certificate: %w", err)
   128  	}
   129  	return &tls.Certificate{
   130  		Certificate: [][]byte{x509c.Raw, ca.Raw},
   131  		PrivateKey:  priv,
   132  		Leaf:        x509c,
   133  	}, nil
   134  }