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 }