local-server/vendor/github.com/cloudflare/cfssl/initca/initca_test.go
Mikaël Cluseau 4d889632f6 vendor
2018-06-17 18:32:44 +11:00

386 lines
9.0 KiB
Go

package initca
import (
"bytes"
"crypto/ecdsa"
"crypto/rsa"
"io/ioutil"
"strings"
"testing"
"time"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/signer"
"github.com/cloudflare/cfssl/signer/local"
)
var validKeyParams = []csr.BasicKeyRequest{
{A: "rsa", S: 2048},
{A: "rsa", S: 3072},
{A: "rsa", S: 4096},
{A: "ecdsa", S: 256},
{A: "ecdsa", S: 384},
{A: "ecdsa", S: 521},
}
var validCAConfigs = []csr.CAConfig{
{PathLength: 0, PathLenZero: true},
{PathLength: 0, PathLenZero: false},
{PathLength: 2},
{PathLength: 2, Expiry: "1h"},
// invalid PathLenZero value will be ignored
{PathLength: 2, PathLenZero: true},
}
var invalidCAConfig = csr.CAConfig{
PathLength: 2,
// Expiry must be a duration string
Expiry: "2116/12/31",
}
var csrFiles = []string{
"testdata/rsa2048.csr",
"testdata/rsa3072.csr",
"testdata/rsa4096.csr",
"testdata/ecdsa256.csr",
"testdata/ecdsa384.csr",
"testdata/ecdsa521.csr",
}
var testRSACAFile = "testdata/5min-rsa.pem"
var testRSACAKeyFile = "testdata/5min-rsa-key.pem"
var testECDSACAFile = "testdata/5min-ecdsa.pem"
var testECDSACAKeyFile = "testdata/5min-ecdsa-key.pem"
var invalidCryptoParams = []csr.BasicKeyRequest{
// Weak Key
{A: "rsa", S: 1024},
// Bad param
{A: "rsaCrypto", S: 2048},
{A: "ecdsa", S: 2000},
}
func TestInitCA(t *testing.T) {
var req *csr.CertificateRequest
hostname := "cloudflare.com"
for _, param := range validKeyParams {
for _, caconfig := range validCAConfigs {
req = &csr.CertificateRequest{
Names: []csr.Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: hostname,
Hosts: []string{hostname, "www." + hostname},
KeyRequest: &param,
CA: &caconfig,
}
certBytes, _, keyBytes, err := New(req)
if err != nil {
t.Fatal("InitCA failed:", err)
}
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
if err != nil {
t.Fatal("InitCA private key parsing failed:", err)
}
cert, err := helpers.ParseCertificatePEM(certBytes)
if err != nil {
t.Fatal("InitCA cert parsing failed:", err)
}
// Verify key parameters.
switch req.KeyRequest.Algo() {
case "rsa":
if cert.PublicKey.(*rsa.PublicKey).N.BitLen() != param.Size() {
t.Fatal("Cert key length mismatch.")
}
if key.(*rsa.PrivateKey).N.BitLen() != param.Size() {
t.Fatal("Private key length mismatch.")
}
case "ecdsa":
if cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().BitSize != param.Size() {
t.Fatal("Cert key length mismatch.")
}
if key.(*ecdsa.PrivateKey).Curve.Params().BitSize != param.Size() {
t.Fatal("Private key length mismatch.")
}
}
// Verify CA MaxPathLen
if caconfig.PathLength == 0 && cert.MaxPathLenZero != caconfig.PathLenZero {
t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect %v, got %v", caconfig.PathLenZero, cert.MaxPathLenZero)
}
if caconfig.PathLength != 0 {
if cert.MaxPathLen != caconfig.PathLength {
t.Fatalf("fail to init a CA cert with specified CA pathlen: expect %d, got %d", caconfig.PathLength, cert.MaxPathLen)
}
if cert.MaxPathLenZero != false {
t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect false, got %t", cert.MaxPathLenZero)
}
}
// Replace the default CAPolicy with a test (short expiry) version.
CAPolicy = func() *config.Signing {
return &config.Signing{
Default: &config.SigningProfile{
Usage: []string{"cert sign", "crl sign"},
ExpiryString: "300s",
Expiry: 300 * time.Second,
CAConstraint: config.CAConstraint{IsCA: true},
},
}
}
// Start a signer
s, err := local.NewSigner(key, cert, signer.DefaultSigAlgo(key), nil)
if err != nil {
t.Fatal("Signer Creation error:", err)
}
s.SetPolicy(CAPolicy())
// Sign RSA and ECDSA customer CSRs.
for _, csrFile := range csrFiles {
csrBytes, err := ioutil.ReadFile(csrFile)
if err != nil {
t.Fatal("CSR loading error:", err)
}
req := signer.SignRequest{
Request: string(csrBytes),
Hosts: signer.SplitHosts(hostname),
Profile: "",
Label: "",
}
bytes, err := s.Sign(req)
if err != nil {
t.Fatal(err)
}
customerCert, _ := helpers.ParseCertificatePEM(bytes)
if customerCert.SignatureAlgorithm != s.SigAlgo() {
t.Fatal("Signature Algorithm mismatch")
}
err = customerCert.CheckSignatureFrom(cert)
if err != nil {
t.Fatal("Signing CSR failed.", err)
}
}
}
}
}
func TestInvalidCAConfig(t *testing.T) {
hostname := "example.com"
req := &csr.CertificateRequest{
Names: []csr.Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: hostname,
Hosts: []string{hostname, "www." + hostname},
KeyRequest: &validKeyParams[0],
CA: &invalidCAConfig,
}
_, _, _, err := New(req)
if err == nil {
t.Fatal("InitCA with bad CAConfig should fail:", err)
}
}
func TestInvalidCryptoParams(t *testing.T) {
var req *csr.CertificateRequest
hostname := "cloudflare.com"
for _, invalidParam := range invalidCryptoParams {
req = &csr.CertificateRequest{
Names: []csr.Name{
{
C: "US",
ST: "California",
L: "San Francisco",
O: "CloudFlare",
OU: "Systems Engineering",
},
},
CN: hostname,
Hosts: []string{hostname, "www." + hostname},
KeyRequest: &invalidParam,
}
_, _, _, err := New(req)
if err == nil {
t.Fatal("InitCA with bad params should fail:", err)
}
if !strings.Contains(err.Error(), `"code":2400`) {
t.Fatal(err)
}
}
}
type validation struct {
r *csr.CertificateRequest
v bool
}
var testValidations = []validation{
{&csr.CertificateRequest{}, false},
{&csr.CertificateRequest{
CN: "test CA",
}, true},
{&csr.CertificateRequest{
Names: []csr.Name{{}},
}, false},
{&csr.CertificateRequest{
Names: []csr.Name{
{O: "Example CA"},
},
}, true},
}
func TestValidations(t *testing.T) {
for i, tv := range testValidations {
err := validator(tv.r)
if tv.v && err != nil {
t.Fatalf("%v", err)
}
if !tv.v && err == nil {
t.Fatalf("%d: expected error, but no error was reported", i)
}
}
}
func TestRenewRSA(t *testing.T) {
certPEM, err := RenewFromPEM(testRSACAFile, testRSACAKeyFile)
if err != nil {
t.Fatal(err)
}
// must parse ok
cert, err := helpers.ParseCertificatePEM(certPEM)
if err != nil {
t.Fatal(err)
}
if !cert.IsCA {
t.Fatal("renewed CA certificate is not CA")
}
// cert expiry must be 5 minutes
expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds()
if expiry >= 301 || expiry <= 299 {
t.Fatal("expiry is not correct:", expiry)
}
// check subject
if cert.Subject.CommonName != "" {
t.Fatal("Bad CommonName")
}
if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" {
t.Fatal("Bad Subject")
}
if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." {
t.Fatal("Bad Subject")
}
}
func TestRenewECDSA(t *testing.T) {
certPEM, err := RenewFromPEM(testECDSACAFile, testECDSACAKeyFile)
if err != nil {
t.Fatal(err)
}
// must parse ok
cert, err := helpers.ParseCertificatePEM(certPEM)
if err != nil {
t.Fatal(err)
}
if !cert.IsCA {
t.Fatal("renewed CA certificate is not CA")
}
// cert expiry must be 5 minutes
expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds()
if expiry >= 301 || expiry <= 299 {
t.Fatal("expiry is not correct:", expiry)
}
// check subject
if cert.Subject.CommonName != "" {
t.Fatal("Bad CommonName")
}
if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" {
t.Fatal("Bad Subject")
}
if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." {
t.Fatal("Bad Subject")
}
}
func TestRenewMismatch(t *testing.T) {
_, err := RenewFromPEM(testECDSACAFile, testRSACAKeyFile)
if err == nil {
t.Fatal("Fail to detect cert/key mismatch")
}
}
func TestRenew(t *testing.T) {
in, err := ioutil.ReadFile(testECDSACAFile)
if err != nil {
t.Fatal(err)
}
cert, err := helpers.ParseCertificatePEM(in)
if err != nil {
t.Fatal(err)
}
in, err = ioutil.ReadFile(testECDSACAKeyFile)
if err != nil {
t.Fatal(err)
}
priv, err := helpers.ParsePrivateKeyPEM(in)
if err != nil {
t.Fatal(err)
}
renewed, err := Update(cert, priv)
if err != nil {
t.Fatal(err)
}
newCert, err := helpers.ParseCertificatePEM(renewed)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(newCert.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) {
t.Fatal("Update returned a certificate with different subject public key info")
}
if !bytes.Equal(newCert.RawSubject, cert.RawSubject) {
t.Fatal("Update returned a certificate with different subject info")
}
if !bytes.Equal(newCert.RawIssuer, cert.RawIssuer) {
t.Fatal("Update returned a certificate with different issuer info")
}
}