github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/security/test_util.go (about) 1 // Copyright 2021 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package security 15 16 import ( 17 "bytes" 18 "crypto/rand" 19 "crypto/rsa" 20 "crypto/x509" 21 "crypto/x509/pkix" 22 "encoding/pem" 23 "math/big" 24 "net" 25 "os" 26 "time" 27 ) 28 29 // WriteFile write content to a temp file 30 func WriteFile(fileName string, content []byte) (path string, err error) { 31 cert, err := os.CreateTemp("", fileName) 32 if err != nil { 33 return "", err 34 } 35 _, err = cert.Write(content) 36 return cert.Name(), err 37 } 38 39 // NewServerCredential4Test return a Credential for testing 40 func NewServerCredential4Test(cn string) (*CA, *Credential, error) { 41 var caPath, certPath, keyPath string 42 43 ca, err := NewCA() 44 if err != nil { 45 return nil, nil, err 46 } 47 if caPath, err = WriteFile("ticdc-test-ca", ca.CAPEM); err != nil { 48 return nil, nil, err 49 } 50 51 certPEM, keyPEM, err := ca.GenerateCerts(cn) 52 if err != nil { 53 return nil, nil, err 54 } 55 if certPath, err = WriteFile("ticdc-test-cert", certPEM); err != nil { 56 return nil, nil, err 57 } 58 if keyPath, err = WriteFile("ticdc-test-key", keyPEM); err != nil { 59 return nil, nil, err 60 } 61 62 res := &Credential{ 63 CAPath: caPath, 64 CertPath: certPath, 65 KeyPath: keyPath, 66 } 67 if cn != "" { 68 res.CertAllowedCN = append(res.CertAllowedCN, cn) 69 } 70 return ca, res, nil 71 } 72 73 // CA represents a certificate authority 74 type CA struct { 75 privateKey *rsa.PrivateKey 76 77 Cert *x509.Certificate 78 CAPEM []byte 79 } 80 81 // NewCA create a new CA 82 func NewCA() (*CA, error) { 83 caPrivKey, err := rsa.GenerateKey(rand.Reader, 2048) 84 if err != nil { 85 return nil, err 86 } 87 88 caCert := &x509.Certificate{ 89 SerialNumber: big.NewInt(2019), 90 Subject: pkix.Name{ 91 Organization: []string{"test"}, 92 }, 93 NotBefore: time.Now(), 94 NotAfter: time.Now().AddDate(10, 0, 0), 95 IsCA: true, 96 ExtKeyUsage: []x509.ExtKeyUsage{ 97 x509.ExtKeyUsageClientAuth, 98 x509.ExtKeyUsageServerAuth, 99 }, 100 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 101 BasicConstraintsValid: true, 102 } 103 104 // self-signed certificate 105 caBytes, err := x509.CreateCertificate(rand.Reader, caCert, caCert, 106 &caPrivKey.PublicKey, caPrivKey) 107 if err != nil { 108 return nil, err 109 } 110 111 caPem := new(bytes.Buffer) 112 err = pem.Encode(caPem, &pem.Block{ 113 Type: "CERTIFICATE", 114 Bytes: caBytes, 115 }) 116 if err != nil { 117 return nil, err 118 } 119 return &CA{ 120 privateKey: caPrivKey, 121 Cert: caCert, 122 CAPEM: caPem.Bytes(), 123 }, err 124 } 125 126 // GetPrivKeyPEM returns the PEM contents of the private key. 127 func (ca *CA) GetPrivKeyPEM() ([]byte, error) { 128 caPrivKeyPEM := new(bytes.Buffer) 129 err := pem.Encode(caPrivKeyPEM, &pem.Block{ 130 Type: "RSA PRIVATE KEY", 131 Bytes: x509.MarshalPKCS1PrivateKey(ca.privateKey), 132 }) 133 if err != nil { 134 return nil, err 135 } 136 return caPrivKeyPEM.Bytes(), nil 137 } 138 139 // GenerateCerts returns the PEM contents of a CA certificate and some certificates 140 // and private keys per Common Name in commonNames. 141 // thanks to https://shaneutt.com/blog/golang-ca-and-signed-cert-go/. 142 func (ca *CA) GenerateCerts(commonName string) (certPEM, KeyPEM []byte, err error) { 143 certPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) 144 if err != nil { 145 return nil, nil, err 146 } 147 148 cert := &x509.Certificate{ 149 SerialNumber: big.NewInt(1658), 150 Subject: pkix.Name{ 151 Organization: []string{"test"}, 152 CommonName: commonName, 153 }, 154 IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}, 155 NotBefore: time.Now(), 156 NotAfter: time.Now().AddDate(10, 0, 0), 157 SubjectKeyId: []byte{1, 2, 3, 4, 6}, 158 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, 159 KeyUsage: x509.KeyUsageDigitalSignature, 160 } 161 162 // signing the certificate with CA 163 certBytes, err := x509.CreateCertificate(rand.Reader, cert, ca.Cert, 164 &certPrivKey.PublicKey, ca.privateKey) 165 if err != nil { 166 return nil, nil, err 167 } 168 169 certPEMBuffer := new(bytes.Buffer) 170 err = pem.Encode(certPEMBuffer, &pem.Block{ 171 Type: "CERTIFICATE", 172 Bytes: certBytes, 173 }) 174 if err != nil { 175 return nil, nil, err 176 } 177 178 keyPEMBuffer := new(bytes.Buffer) 179 err = pem.Encode(keyPEMBuffer, &pem.Block{ 180 Type: "RSA PRIVATE KEY", 181 Bytes: x509.MarshalPKCS1PrivateKey(certPrivKey), 182 }) 183 if err != nil { 184 return nil, nil, err 185 } 186 187 return certPEMBuffer.Bytes(), keyPEMBuffer.Bytes(), nil 188 }