go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/internal/test/certs.go (about) 1 // Copyright 2022 The Mangos Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use 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 O R 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 test 16 17 import ( 18 "crypto/ed25519" 19 "crypto/rand" 20 "crypto/tls" 21 "crypto/x509" 22 "crypto/x509/pkix" 23 "encoding/pem" 24 "math/big" 25 "net" 26 "sync" 27 "testing" 28 "time" 29 ) 30 31 // KeyPair is a single public key pair 32 type KeyPair struct { 33 cert *x509.Certificate 34 pair tls.Certificate 35 certDER []byte 36 pubKey ed25519.PublicKey 37 prvKey ed25519.PrivateKey 38 } 39 40 // Keys is a set of the Root, Server, and Client keys for a test config. 41 type Keys struct { 42 Root KeyPair // Root CA key pair 43 Server KeyPair // Server key pair 44 Client KeyPair // Client key pair 45 } 46 47 func (k *KeyPair) CertPEM() []byte { 48 return pem.EncodeToMemory(&pem.Block{ 49 Type: "CERTIFICATE", 50 Headers: nil, 51 Bytes: k.certDER, 52 }) 53 } 54 55 func (k *KeyPair) KeyPEM() []byte { 56 57 b, err := x509.MarshalPKCS8PrivateKey(k.prvKey) 58 if err != nil { 59 return nil 60 } 61 62 return pem.EncodeToMemory(&pem.Block{ 63 Type: "PRIVATE KEY", 64 Bytes: b, 65 }) 66 } 67 68 func (k *KeyPair) PubKeyPEM() []byte { 69 b, err := x509.MarshalPKIXPublicKey(k.pubKey) 70 if err != nil { 71 return nil 72 } 73 74 return pem.EncodeToMemory(&pem.Block{ 75 Type: "PUBLIC KEY", 76 Bytes: b, 77 }) 78 } 79 80 func (k *KeyPair) genKey() (err error) { 81 if k.pubKey, k.prvKey, err = ed25519.GenerateKey(rand.Reader); err != nil { 82 return 83 } 84 return 85 } 86 87 func (k *KeyPair) genCert(tmpl *x509.Certificate, parent *KeyPair) (err error) { 88 k.cert = tmpl // for self-signed, we pass ourselves as parent, this makes it work 89 k.certDER, err = x509.CreateCertificate(rand.Reader, tmpl, parent.cert, k.pubKey, parent.prvKey) 90 if err != nil { 91 return 92 } 93 if k.cert, err = x509.ParseCertificate(k.certDER); err != nil { 94 return 95 } 96 k.pair = tls.Certificate{ 97 Certificate: [][]byte{k.certDER}, 98 PrivateKey: k.prvKey, 99 Leaf: k.cert, 100 } 101 return 102 } 103 104 func newKeys() (k *Keys, err error) { 105 k = &Keys{} 106 if err = k.Root.genKey(); err != nil { 107 return nil, err 108 } 109 if err = k.Server.genKey(); err != nil { 110 return nil, err 111 } 112 if err = k.Client.genKey(); err != nil { 113 return nil, err 114 } 115 116 if err = k.Root.genCert(rootTmpl, &k.Root); err != nil { 117 return nil, err 118 } 119 if err = k.Server.genCert(serverTmpl, &k.Root); err != nil { 120 return nil, err 121 } 122 if err = k.Client.genCert(clientTmpl, &k.Root); err != nil { 123 return nil, err 124 } 125 126 return k, nil 127 } 128 129 var rootTmpl = &x509.Certificate{ 130 SerialNumber: big.NewInt(1), 131 132 Issuer: pkix.Name{ 133 CommonName: "issuer.mangos.example.com", 134 Organization: []string{"Mangos Issuer Org"}, 135 }, 136 Subject: pkix.Name{ 137 CommonName: "Root.mangos.example.com", 138 Organization: []string{"Mangos Root Org"}, 139 }, 140 NotBefore: time.Unix(1000, 0), 141 NotAfter: time.Now().Add(time.Hour), 142 IsCA: true, 143 BasicConstraintsValid: true, 144 OCSPServer: []string{"ocsp.mangos.example.com"}, 145 DNSNames: []string{"Root.mangos.example.com"}, 146 IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, 147 SignatureAlgorithm: x509.PureEd25519, 148 KeyUsage: x509.KeyUsageCertSign, 149 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 150 } 151 152 var serverTmpl = &x509.Certificate{ 153 SerialNumber: big.NewInt(2), 154 155 Issuer: pkix.Name{ 156 CommonName: "issuer.mangos.example.com", 157 Organization: []string{"Mangos Issuer Org"}, 158 }, 159 Subject: pkix.Name{ 160 CommonName: "Server.mangos.example.com", 161 Organization: []string{"Mangos Server Org"}, 162 }, 163 NotBefore: time.Unix(1000, 0), 164 NotAfter: time.Now().Add(time.Hour), 165 IsCA: false, 166 OCSPServer: []string{"ocsp.mangos.example.com"}, 167 DNSNames: []string{"Server.mangos.example.com"}, 168 IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, 169 SignatureAlgorithm: x509.PureEd25519, 170 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 171 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 172 } 173 174 var clientTmpl = &x509.Certificate{ 175 SerialNumber: big.NewInt(3), 176 177 Issuer: pkix.Name{ 178 CommonName: "issuer.mangos.example.com", 179 Organization: []string{"Mangos Issuer Org"}, 180 }, 181 Subject: pkix.Name{ 182 CommonName: "Client.mangos.example.com", 183 Organization: []string{"Mangos Client Org"}, 184 }, 185 NotBefore: time.Unix(1000, 0), 186 NotAfter: time.Now().Add(time.Hour), 187 IsCA: false, 188 OCSPServer: []string{"ocsp.mangos.example.com"}, 189 DNSNames: []string{"Client.mangos.example.com"}, 190 IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, 191 SignatureAlgorithm: x509.PureEd25519, 192 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 193 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 194 } 195 196 // NewTLSConfig creates a suitable TLS configuration, using 197 // either a Server or Client. 198 func NewTLSConfig() (*tls.Config, *tls.Config, *Keys, error) { 199 srvCfg := &tls.Config{} 200 cliCfg := &tls.Config{} 201 202 keys, err := newKeys() 203 if err != nil { 204 return nil, nil, nil, err 205 } 206 207 // Server side config. 208 srvCfg.Certificates = append(srvCfg.Certificates, keys.Server.pair) 209 210 // Client side config. 211 cliCfg.Certificates = append(cliCfg.Certificates, keys.Client.pair) 212 213 // Now configure the things the Client needs to know -- the self-signed 214 // Root CA, and also the Server's identity. 215 cliCfg.ServerName = "127.0.0.1" 216 cliCfg.RootCAs = x509.NewCertPool() 217 cliCfg.RootCAs.AddCert(keys.Root.cert) 218 return srvCfg, cliCfg, keys, nil 219 } 220 221 var lock sync.Mutex 222 var clientConfig *tls.Config 223 var serverConfig *tls.Config 224 var keys *Keys 225 226 // GetTLSConfig is like NewTLSConfig, but it caches to avoid regenerating 227 // key material pointlessly. 228 func GetTLSConfig(t *testing.T, server bool) *tls.Config { 229 var err error 230 lock.Lock() 231 defer lock.Unlock() 232 233 if serverConfig == nil || clientConfig == nil || keys == nil { 234 serverConfig, clientConfig, keys, err = NewTLSConfig() 235 MustSucceed(t, err) 236 } 237 if server { 238 return serverConfig 239 } 240 return clientConfig 241 } 242 243 // GetTLSConfigKeys is like NewTLSConfig, but it caches to avoid regenerating 244 // key material pointlessly. It also returns the Keys. 245 func GetTLSConfigKeys(t *testing.T) (*tls.Config, *tls.Config, *Keys) { 246 var err error 247 lock.Lock() 248 defer lock.Unlock() 249 250 if serverConfig == nil || clientConfig == nil || keys == nil { 251 serverConfig, clientConfig, keys, err = NewTLSConfig() 252 MustSucceed(t, err) 253 } 254 return serverConfig, clientConfig, keys 255 }