github.com/grailbio/base@v0.0.11/security/tls/certificateauthority/tls_test.go (about)

     1  // Copyright 2018 GRAIL, Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache-2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package certificateauthority
     6  
     7  import (
     8  	"crypto/x509"
     9  	"io/ioutil"
    10  	"net"
    11  	"reflect"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/grailbio/base/security/keycrypt"
    16  )
    17  
    18  func TestAuthority(t *testing.T) {
    19  	margin := 60 * time.Second
    20  	certPEM, err := ioutil.ReadFile("testdata/cert.pem")
    21  	if err != nil {
    22  		panic(err)
    23  	}
    24  	ca := CertificateAuthority{DriftMargin: margin, Signer: keycrypt.Static(certPEM)}
    25  	if err := ca.Init(); err != nil {
    26  		t.Fatal(err)
    27  	}
    28  	ips := []net.IP{net.IPv4(1, 2, 3, 4)}
    29  	dnses := []string{"test.grail.com"}
    30  	certBytes, priv, err := ca.Issue("test", 10*time.Minute, ips, dnses)
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	cert, err := x509.ParseCertificate(certBytes)
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  
    39  	now := time.Now()
    40  	opts := x509.VerifyOptions{}
    41  	opts.Roots = x509.NewCertPool()
    42  	opts.Roots.AddCert(ca.Cert)
    43  	if _, err := cert.Verify(opts); err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	if err := priv.Validate(); err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	if got, want := priv.Public(), cert.PublicKey; !reflect.DeepEqual(got, want) {
    50  		t.Errorf("got %v, want %v", got, want)
    51  	}
    52  	if got, want := cert.Subject.CommonName, "test"; got != want {
    53  		t.Errorf("got %q, want %q", got, want)
    54  	}
    55  	if got, want := cert.NotBefore, now.Add(-margin); want.Before(got) {
    56  		t.Errorf("wanted %s <= %s", got, want)
    57  	}
    58  	if got, want := cert.NotAfter.Sub(cert.NotBefore), 10*time.Minute+margin; got != want {
    59  		t.Errorf("got %s, want %s", got, want)
    60  	}
    61  	if cert.IsCA {
    62  		t.Error("cert is CA")
    63  	}
    64  	if got, want := cert.IPAddresses, ips; !ipsEqual(got, want) {
    65  		t.Errorf("got %v, want %v", got, want)
    66  	}
    67  	if got, want := cert.DNSNames, dnses; !reflect.DeepEqual(got, want) {
    68  		t.Errorf("got %v, want %v", got, want)
    69  	}
    70  	keyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
    71  	if got, want := cert.ExtKeyUsage, keyUsage; !reflect.DeepEqual(got, want) {
    72  		t.Errorf("got %v, want %v", got, want)
    73  	}
    74  }
    75  
    76  func TestAuthorityServerExtKeyUsage(t *testing.T) {
    77  	margin := 60 * time.Second
    78  	certPEM, err := ioutil.ReadFile("testdata/cert.pem")
    79  	if err != nil {
    80  		panic(err)
    81  	}
    82  	ca := CertificateAuthority{DriftMargin: margin, Signer: keycrypt.Static(certPEM)}
    83  	if err := ca.Init(); err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	ips := []net.IP{net.IPv4(1, 2, 3, 4)}
    87  	dnses := []string{"test.grail.com"}
    88  	keyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
    89  	certBytes, priv, err := ca.IssueWithKeyUsage("test", 10*time.Minute, ips, dnses, keyUsage)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  	cert, err := x509.ParseCertificate(certBytes)
    94  	if err != nil {
    95  		t.Fatal(err)
    96  	}
    97  	opts := x509.VerifyOptions{}
    98  	opts.Roots = x509.NewCertPool()
    99  	opts.Roots.AddCert(ca.Cert)
   100  	if _, err := cert.Verify(opts); err != nil {
   101  		t.Fatal(err)
   102  	}
   103  	if err := priv.Validate(); err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	if got, want := cert.ExtKeyUsage, keyUsage; !reflect.DeepEqual(got, want) {
   107  		t.Errorf("got %v, want %v", got, want)
   108  	}
   109  }
   110  
   111  func TestAuthorityClientExtKeyUsage(t *testing.T) {
   112  	margin := 60 * time.Second
   113  	certPEM, err := ioutil.ReadFile("testdata/cert.pem")
   114  	if err != nil {
   115  		panic(err)
   116  	}
   117  	ca := CertificateAuthority{DriftMargin: margin, Signer: keycrypt.Static(certPEM)}
   118  	if err := ca.Init(); err != nil {
   119  		t.Fatal(err)
   120  	}
   121  	ips := []net.IP{net.IPv4(1, 2, 3, 4)}
   122  	dnses := []string{"test.grail.com"}
   123  	keyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
   124  	certBytes, priv, err := ca.IssueWithKeyUsage("test", 10*time.Minute, ips, dnses, keyUsage)
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	cert, err := x509.ParseCertificate(certBytes)
   129  	if err != nil {
   130  		t.Fatal(err)
   131  	}
   132  	opts := x509.VerifyOptions{}
   133  	opts.Roots = x509.NewCertPool()
   134  	opts.Roots.AddCert(ca.Cert)
   135  	// Client certs can not be verified as a server, expect verification fail.
   136  	if _, err := cert.Verify(opts); err == nil {
   137  		t.Fatal("unexpected valid X509 certificate.")
   138  	}
   139  	if err := priv.Validate(); err != nil {
   140  		t.Fatal(err)
   141  	}
   142  	if got, want := cert.ExtKeyUsage, keyUsage; !reflect.DeepEqual(got, want) {
   143  		t.Errorf("got %v, want %v", got, want)
   144  	}
   145  }
   146  
   147  func ipsEqual(x, y []net.IP) bool {
   148  	if len(x) != len(y) {
   149  		return false
   150  	}
   151  	for i := range x {
   152  		if !x[i].Equal(y[i]) {
   153  			return false
   154  		}
   155  	}
   156  	return true
   157  }