dragonfly/manager/rpcserver/security_server_v1_test.go

174 lines
4.5 KiB
Go

/*
* Copyright 2023 The Dragonfly Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rpcserver
import (
"bytes"
"context"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"testing"
"time"
testifyassert "github.com/stretchr/testify/assert"
testifyrequire "github.com/stretchr/testify/require"
"google.golang.org/grpc/peer"
"google.golang.org/protobuf/types/known/durationpb"
securityv1 "d7y.io/api/pkg/apis/security/v1"
)
func TestIssueCertificate(t *testing.T) {
assert := testifyassert.New(t)
require := testifyrequire.New(t)
caCert, caKey := genCA()
testCases := []struct {
name string
peerIP string
}{
{
name: "ipv4",
peerIP: "1.1.1.1",
},
{
name: "ipv6",
peerIP: "1::1",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
template := &x509.CertificateRequest{
Subject: pkix.Name{
Country: []string{"China"},
Organization: []string{"Dragonfly"},
OrganizationalUnit: []string{"Development"},
},
}
pk, err := rsa.GenerateKey(rand.Reader, 4096)
require.Nilf(err, "GenerateKey should be ok")
csr, err := x509.CreateCertificateRequest(rand.Reader, template, pk)
require.Nilf(err, "CreateCertificateRequest should be ok")
ca, err := tls.X509KeyPair([]byte(caCert), []byte(caKey))
require.Nilf(err, "parse cert and private key should be ok")
x509CACert, err := x509.ParseCertificate(ca.Certificate[0])
if err != nil {
t.Fatal(err)
}
securityServerV1 := newSecurityServerV1(&SelfSignedCert{
TLSCert: &ca,
X509Cert: x509CACert,
CertChain: ca.Certificate,
})
require.Nilf(err, "newServer should be ok")
ctx := peer.NewContext(
context.Background(),
&peer.Peer{
Addr: &net.TCPAddr{
IP: net.ParseIP(tc.peerIP),
Port: 65008,
},
})
resp, err := securityServerV1.IssueCertificate(
ctx,
&securityv1.CertificateRequest{
Csr: csr,
ValidityPeriod: durationpb.New(time.Hour),
})
assert.Nilf(err, "IssueCertificate should be ok")
assert.NotNilf(resp, "IssueCertificate should not be nil")
assert.Equal(len(resp.CertificateChain), 2)
cert := readCert(resp.CertificateChain[0])
assert.Equal(len(cert.IPAddresses), 1)
assert.True(cert.IPAddresses[0].Equal(net.ParseIP(tc.peerIP)))
assert.Equal(cert.KeyUsage, x509.KeyUsageDigitalSignature|x509.KeyUsageDataEncipherment|x509.KeyUsageKeyEncipherment)
assert.Equal(cert.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth})
})
}
}
func genCA() (cert, key string) {
pk, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
panic(err)
}
ca := &x509.Certificate{
SerialNumber: big.NewInt(2022),
Subject: pkix.Name{
Country: []string{"China"},
Organization: []string{"Dragonfly"},
OrganizationalUnit: []string{"Development"},
Locality: []string{"Hangzhou"},
Province: []string{"Zhejiang"},
},
NotBefore: time.Now().Add(-10 * time.Minute).UTC(),
NotAfter: time.Now().Add(time.Hour).UTC(),
BasicConstraintsValid: true,
IsCA: true,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
}
caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &pk.PublicKey, pk)
if err != nil {
panic(err)
}
var (
caCertPEM bytes.Buffer
caPrivateKeyPEM bytes.Buffer
)
if err = pem.Encode(&caCertPEM, &pem.Block{Type: "CERTIFICATE", Bytes: caBytes}); err != nil {
panic(err)
}
if err = pem.Encode(&caPrivateKeyPEM, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)}); err != nil {
panic(err)
}
key, cert = caPrivateKeyPEM.String(), caCertPEM.String()
return
}
func readCert(der []byte) *x509.Certificate {
cert, err := x509.ParseCertificate(der)
if err != nil {
panic(err)
}
return cert
}