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  }