github.com/replicatedhq/ship@v0.55.0/pkg/util/certs_test.go (about)

     1  package util
     2  
     3  import (
     4  	"crypto/tls"
     5  	"crypto/x509"
     6  	"encoding/pem"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/cloudflare/cfssl/csr"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func Test_makeKeyRequest(t *testing.T) {
    15  
    16  	tests := []struct {
    17  		name     string
    18  		certKind string
    19  		want     csr.BasicKeyRequest
    20  		wantErr  bool
    21  	}{
    22  		{
    23  			name:     "empty kind",
    24  			certKind: "",
    25  			want: csr.BasicKeyRequest{
    26  				A: "rsa",
    27  				S: 2048,
    28  			},
    29  		},
    30  		{
    31  			name:     "rsa",
    32  			certKind: "rsa-2567",
    33  			want: csr.BasicKeyRequest{
    34  				A: "rsa",
    35  				S: 2567,
    36  			},
    37  		},
    38  		{
    39  			name:     "P256",
    40  			certKind: "P256",
    41  			want: csr.BasicKeyRequest{
    42  				A: "ecdsa",
    43  				S: 256,
    44  			},
    45  		},
    46  		{
    47  			name:     "P384",
    48  			certKind: "P384",
    49  			want: csr.BasicKeyRequest{
    50  				A: "ecdsa",
    51  				S: 384,
    52  			},
    53  		},
    54  		{
    55  			name:     "P521",
    56  			certKind: "P521",
    57  			want: csr.BasicKeyRequest{
    58  				A: "ecdsa",
    59  				S: 521,
    60  			},
    61  		},
    62  		{
    63  			name:     "P224 - not acceptable",
    64  			certKind: "P224",
    65  			wantErr:  true,
    66  		},
    67  		{
    68  			name:     "nonsense",
    69  			certKind: "nonsense",
    70  			wantErr:  true,
    71  		},
    72  	}
    73  	for _, tt := range tests {
    74  		t.Run(tt.name, func(t *testing.T) {
    75  			req := require.New(t)
    76  			got, err := makeKeyRequest(tt.certKind)
    77  			if tt.wantErr {
    78  				req.Error(err)
    79  				return
    80  			}
    81  			req.NoError(err)
    82  			req.Equal(tt.want, got)
    83  		})
    84  	}
    85  }
    86  
    87  func TestMakeCA(t *testing.T) {
    88  	tests := []struct {
    89  		name   string
    90  		caKind string
    91  	}{
    92  		{
    93  			name:   "empty kind",
    94  			caKind: "",
    95  		},
    96  		{
    97  			name:   "rsa",
    98  			caKind: "rsa-4096",
    99  		},
   100  		{
   101  			name:   "P256",
   102  			caKind: "P256",
   103  		},
   104  		{
   105  			name:   "P384",
   106  			caKind: "P384",
   107  		},
   108  		{
   109  			name:   "P521",
   110  			caKind: "P521",
   111  		},
   112  	}
   113  	for _, tt := range tests {
   114  		t.Run(tt.name, func(t *testing.T) {
   115  			req := require.New(t)
   116  
   117  			ca, err := MakeCA(tt.caKind)
   118  			req.NoError(err)
   119  
   120  			// validate ca was generated properly
   121  			_, err = tls.X509KeyPair([]byte(ca.Cert), []byte(ca.Key))
   122  			req.NoError(err)
   123  
   124  			block, _ := pem.Decode([]byte(ca.Cert))
   125  			req.NotEqual(nil, block)
   126  			parsedCA, err := x509.ParseCertificate(block.Bytes)
   127  			req.NoError(err, "parse CA certificate")
   128  
   129  			req.True(parsedCA.IsCA, "generated CA must be a CA")
   130  
   131  			caDuration, err := TimeToExpire([]byte(ca.Cert))
   132  			req.NoError(err, "calculate time to expire")
   133  			req.True(caDuration > (5*365*24-1)*time.Hour, "ca should expire in at least 5 years")
   134  		})
   135  	}
   136  }
   137  
   138  func TestRenewCA(t *testing.T) {
   139  	tests := []struct {
   140  		name    string
   141  		inputCA CAType
   142  	}{
   143  		{
   144  			name: "empty kind",
   145  			inputCA: CAType{
   146  				Cert: `-----BEGIN CERTIFICATE-----
   147  MIIDADCCAeigAwIBAgIUXeGZuN9UjeF8oQEmvY+si5V8K3IwDQYJKoZIhvcNAQEL
   148  BQAwGDEWMBQGA1UEAwwNZ2F0ZWtlZXBlcl9jYTAeFw0xOTEwMTgyMDQwMDBaFw0y
   149  NDEwMTYyMDQwMDBaMBgxFjAUBgNVBAMMDWdhdGVrZWVwZXJfY2EwggEiMA0GCSqG
   150  SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVUQxjYBhdU02GFmoDk5R6q/i7zKXwxnTQ
   151  I88lA4ehYfyej7uEi/xKLm8oKkYzDz0OU8H6ysE7ySaVFnkA6X5kryFwsn9bxKwx
   152  RcWP5fvMOJpQuPfL6eqTNnGQd2UNyzbsK5tmfgYX2oXxragNx8KttWciXrUXlZn+
   153  toyIHm14jmwvdsxyEYxmR3jaI42IDUHoPBcbVhYd7w37zHwVQ0qTe41/eXLnJfRI
   154  /IKYB3Nu/Nda3W2YVyNu0jooX5rbvpQZvcQSMxQtGSC5dd2C+f8mgcdyWryaAHt2
   155  2X1EHob8D3QcgDj/tIbU/onfYDUmVmc0CL3vpUChphU2MGHyEvhZAgMBAAGjQjBA
   156  MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQBcy1F
   157  YnjX9orTbz0Bpw0idCMf1DANBgkqhkiG9w0BAQsFAAOCAQEAn8KAfoZQwHNrFoQD
   158  adlNPXkDb5lFVs/lWpL3RDMAUAFw+cjx/WGjeNs5SMgL5Y4N4tYzwNsjf51bdjCl
   159  WsLm0uql5qBikmrH9u8FHJoCbVFxaqXJS2Ab74QfgmLqkr5HiKWBVUBRt4rI3nO6
   160  23zqUXtiBEpWu+lBYuG40EUE6qd+IfWM7YEtQ2Dn842Iu7hq9U12iIQc03indGVV
   161  vNzM1MXsffhsF1SsJzRkpRn5R1kuAYbWRoyga8BC3I8m6FIr7Bvv0dl+tXad/x1E
   162  ZPuM49d3ZIRBYU1zeCcLDwr7dhUJllUmt4ckPYEBOoCGa7TeczKyG4Ft+QaljNo1
   163  /IGbFA==
   164  -----END CERTIFICATE-----`,
   165  				Key: `-----BEGIN RSA PRIVATE KEY-----
   166  MIIEpAIBAAKCAQEA1VEMY2AYXVNNhhZqA5OUeqv4u8yl8MZ00CPPJQOHoWH8no+7
   167  hIv8Si5vKCpGMw89DlPB+srBO8kmlRZ5AOl+ZK8hcLJ/W8SsMUXFj+X7zDiaULj3
   168  y+nqkzZxkHdlDcs27CubZn4GF9qF8a2oDcfCrbVnIl61F5WZ/raMiB5teI5sL3bM
   169  chGMZkd42iONiA1B6DwXG1YWHe8N+8x8FUNKk3uNf3ly5yX0SPyCmAdzbvzXWt1t
   170  mFcjbtI6KF+a276UGb3EEjMULRkguXXdgvn/JoHHclq8mgB7dtl9RB6G/A90HIA4
   171  /7SG1P6J32A1JlZnNAi976VAoaYVNjBh8hL4WQIDAQABAoIBAQC4J+or+I/QMdRh
   172  iAQp5kRuyvxHFNvFS28ZKXDxIWT7+93c/XUDbt51JDUuVaCY//TT45c5bcT4WiWG
   173  3AnGsc0+Grsh0deFX/rP5s4x9ng0zEDco3K5hc3PHVdZQtno2KEnrlXQW8fi2/J6
   174  vFKy4tu8nzjUQTLRk4OIlAwqjyouwiCu7WfIlK0yNhdvhUILseA2+y3ES2u0GZMk
   175  3Q7tTqRQz1YsCIooNvhZMI6xWgPwO8qCb0wmrJ77QLlxBmPDHp8SjEBg2qp3elxv
   176  0bPKkx+UFeI380NarFzv3OhEHXnpXoIELujZPcYIxpim8pW2yKS9DieBaprbORA3
   177  u9iChSghAoGBANXpV8hpKThdqrakPfqlnroM/wOeVYv/IRsMcPeI6Y/K4u4P6byW
   178  KPpBIoMPuDfsC5oahkx4plKHqKAbsGQ/dy/1nnLFSh9/Dtax12DKvYwDuo3dNw46
   179  AOXtLMIBPfplTRddLpOt6phgux5EwmHWOYcmnLAo/Cf5OAYWvd2xIkJVAoGBAP9J
   180  vZO7K68xnl78KsuFTd8ibvG8eDf0FdUK69SSJzVOflRmi36IOJCV8SWvdEi9nHXr
   181  AT9XDT+rOrO7qAiWUESP8MpHDy8KA91MvPn/wkW6sZ9czxJobwn54S55aQq+VvKz
   182  5PK4AjRJSy/2CZxJO8yiN9zydZqLpyw2liSpoon1AoGBAIpdB9nrI62A8MZ40FpL
   183  PLNNarpVdTI70ZckYgHLPoAzFLw18NN6MYFGFmO+DEOn3A1O8OWP+M1TUGBX6K2/
   184  W4HbFyVXtc1PqzJ2EEFcgmSJmObgWxdJr4EJ+7R1hzhqxAXD0TfW+/KaRw6aHT2Z
   185  itZ/xEQyDoBwtKtDlIZMaEONAoGAco/C9WLPTcV0jqeXBNIDihjHtM+hG2r7ySkn
   186  f7M+yRs6ceG6w8OZrri7CPBdvK7qYbheTPBhz6qlozaZR5E84CfAJOYSmEdkSJFB
   187  VOdDZUtMnnllq5sWCWILfXGag+m61xuHqKyOwKwLg7Bjy7DJlyFM9GgSApKdKKgu
   188  ZLGDcWkCgYBjY/5NwY32IvBEexOIsHLAAnooBWrP2e4kRypPWjT6EuNLKgZOap20
   189  bjuQlSA8ZKeE6ahEev3e9+sF+/MHW/Na8Fnxt2/5WU79lCORrNGd0QkILtfK3fxi
   190  G3dd/SS2uCuC4YRqwnUTODvXC724Tv4YnJ7GYasqBBQqInsJs9aStQ==
   191  -----END RSA PRIVATE KEY-----`,
   192  			},
   193  		},
   194  		{
   195  			name: "rsa 4096",
   196  			inputCA: CAType{
   197  				Cert: `-----BEGIN CERTIFICATE-----
   198  MIIFADCCAuigAwIBAgIUTDWvZgm0Me93CxG/ZFBndBOisZ0wDQYJKoZIhvcNAQEN
   199  BQAwGDEWMBQGA1UEAwwNZ2F0ZWtlZXBlcl9jYTAeFw0xOTEwMTgyMDQwMDBaFw0y
   200  NDEwMTYyMDQwMDBaMBgxFjAUBgNVBAMMDWdhdGVrZWVwZXJfY2EwggIiMA0GCSqG
   201  SIb3DQEBAQUAA4ICDwAwggIKAoICAQCs9H9AtEn9gTkVPr9ae+G0DjjeWEnsjQwZ
   202  VCKYxIXRYl3Z8pLJlguBx3zd7m0JSAXfwm6sArHA8KVr8bUKYwo0u8aWyqMCdzQM
   203  ZWGntVJzJV2Kntn9+AuqcMKByw9YPXOnrZd2c63Zbk54WveuUBnzEzI5Hf0V+ECr
   204  lAc1JWlnBJbs248ZrCLADcPRCSjhK9e5P7OpNI7hfPo0CcEjTmEDJv0Qdp85Vv16
   205  5b3dJC0MICvKOdPt1e0JQ6Yc2a1IcTVOgmGnceTuKmicqlh7WEvNeSODLhuld5cZ
   206  7MWh+pm4GWCi5J/tkiJda3zKJ/aJk4n1FKdcwLdxd1kcdTnof/yJt4pHqkBVdWYI
   207  RtzTnHTZTUGWd7MrJeLfxdJjZyOiRQGxpzSmBO1R0Oow0iOuEYqb6Yfq18aeJhq2
   208  tJS4jyNAnEPmGofZT/1zL+LW2t2l+hHpBV4GP0mAkObBkNZFWaUwoZmvwRCLHmpu
   209  U3NgmCGPXPbHeb2OByBD2xinnl//ojs1QfObtagSHpMpuvSpjeQRE3Q0vDp49wSx
   210  lEXEicIsaXZNfHjrSfsTm2rtDMURHAmtWbe4kVQAJWe+48GOv8G7eTQ72TUAg7iW
   211  6RFTpUcEpithF5LBFKeAUd8BOxT6NH4FDbPtIiRASHbFMDmrs1AZQgB0N3c5k3Ob
   212  GeqbFaCR+wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
   213  /zAdBgNVHQ4EFgQUKjOhMbElTYABle+VETDbHacX6zEwDQYJKoZIhvcNAQENBQAD
   214  ggIBADPY3UNtEex9msSEeQ9lY1QpM+JXnZ0NrodmRYE2l7ofOBb0cD4JYp3DcCdy
   215  hcLdQozi9+1Aj/AllzXEKvgMEqxwK3HTwBnf+W3utXRhioZD5GhqEPSzdTZ1hlkT
   216  IgbXls+UGpJjE4CVYq4JOdhCJlqPQGzHVrQeg90XSKQuOc9r/uig0MrNDazA/oZA
   217  wLSuD7iQC3Fj0j0PjvrzRJT0NpdwoDQSaJzbOp+ZzjzAR8c3TQW2c2CCGkbtA4VK
   218  VXX1zvyTxgAvq5wh/70iMwIVnmvagy3olQwhi77V3j107etQ4j4eg/ZsqqU4CG3W
   219  IrkDqzP/TaRkk3FdtTynolnMqcyDtBN3u0IYudXNR6cTHkLjvghnVud1UQ7RGqFQ
   220  oirCUnnUVwGtuQayy4CpSj16S9KrISeqXQhYQWgsWwQPUGRYH4xVNKJuh87pEpo9
   221  DHZOUte0qLosJMIgCuDRyR4R6BafnSQbU+CZgra1kIVXnGj9Bfi9BhIOxrch3n0o
   222  NB7xNeV/X92araJ7UCa2YETK0wVZ2FXpQ9yl97jE4ji0U1W1IIiPkDyeQbJOlwqC
   223  mV23fPzbnvo6h0DhiB63tIS8Ey9kBZGPJyL5IJA1lWVy2lJNNiKhB9MnQvi2L4xc
   224  XzWZlYz11N/OUc8Q5bmGGKZqm+OiusNQ0in1BZInVcjsyFWq
   225  -----END CERTIFICATE-----`,
   226  				Key: `-----BEGIN RSA PRIVATE KEY-----
   227  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
   276  -----END RSA PRIVATE KEY-----`,
   277  			},
   278  		},
   279  		{
   280  			name: "P256",
   281  			inputCA: CAType{
   282  				Cert: `-----BEGIN CERTIFICATE-----
   283  MIIBczCCARqgAwIBAgIUdP612Ajdfl8Q9zXQqs+KozAH4rswCgYIKoZIzj0EAwIw
   284  GDEWMBQGA1UEAwwNZ2F0ZWtlZXBlcl9jYTAeFw0xOTEwMTgyMDQwMDBaFw0yNDEw
   285  MTYyMDQwMDBaMBgxFjAUBgNVBAMMDWdhdGVrZWVwZXJfY2EwWTATBgcqhkjOPQIB
   286  BggqhkjOPQMBBwNCAATLgGvYeIw9RrCSw6DSK0u79h2H/59vtlb3T10elfdqrZpn
   287  M8YU3DJ2Ug0Vn+BIJm0T4PHIVHlCeZj6AeKLNOV5o0IwQDAOBgNVHQ8BAf8EBAMC
   288  AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUzrZPAi7iJiaqjoVmnVKRE3J/
   289  4vcwCgYIKoZIzj0EAwIDRwAwRAIgOKWLjXsubS20wFg93hEFBz1VReYXByjpYBiZ
   290  2izMjA0CIBU0hUoNCXbXZvQLPjbv0HItKLjz7ZpKlNg5UGTgHGLN
   291  -----END CERTIFICATE-----`,
   292  				Key: `-----BEGIN EC PRIVATE KEY-----
   293  MHcCAQEEIH0Hkd/Fc01eMaG5L/fvguiIP6EKLAViTCYT+YwebkNqoAoGCCqGSM49
   294  AwEHoUQDQgAEy4Br2HiMPUawksOg0itLu/Ydh/+fb7ZW909dHpX3aq2aZzPGFNwy
   295  dlINFZ/gSCZtE+DxyFR5QnmY+gHiizTleQ==
   296  -----END EC PRIVATE KEY-----`,
   297  			},
   298  		},
   299  		{
   300  			name: "P384",
   301  			inputCA: CAType{
   302  				Cert: `-----BEGIN CERTIFICATE-----
   303  MIIBsTCCATegAwIBAgIUd6KnDhvuz/efmwQjtEkxtttl/okwCgYIKoZIzj0EAwMw
   304  GDEWMBQGA1UEAwwNZ2F0ZWtlZXBlcl9jYTAeFw0xOTEwMTgyMDQwMDBaFw0yNDEw
   305  MTYyMDQwMDBaMBgxFjAUBgNVBAMMDWdhdGVrZWVwZXJfY2EwdjAQBgcqhkjOPQIB
   306  BgUrgQQAIgNiAASe4A76K/PvwQGuVe6sFVJZdMvflZGVvfX0GEvbL3UMWXOvOxR6
   307  NZRfVFdeX2Vt7mCf+6WMqLxtV15cCrBolXJstE+/L5xn0QCKOmAKnJ+D0TDa4mBh
   308  3qrDPFhQuYO976GjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
   309  MB0GA1UdDgQWBBRlm/7t8qnnWF86v2BqKtylEexa3DAKBggqhkjOPQQDAwNoADBl
   310  AjEAgGfZa18Wb6fgbTwEAPkfFTA932RwgpUh6a6wwh82KMbYHTMq2tWp9oP4bT2p
   311  No/qAjAYWgZK2M9YyjFNyn7tccV9T2uK5R+PtlVQjncYd8aOQGvcto7ATvJJCP1Q
   312  XfAGt80=
   313  -----END CERTIFICATE-----`,
   314  				Key: `-----BEGIN EC PRIVATE KEY-----
   315  MIGkAgEBBDDMn8BhcufhEp4uCH8M7EksDUMnXg3TGQVXDUhDa89c8IGKneaR90Q0
   316  uKBwm3lhxi6gBwYFK4EEACKhZANiAASe4A76K/PvwQGuVe6sFVJZdMvflZGVvfX0
   317  GEvbL3UMWXOvOxR6NZRfVFdeX2Vt7mCf+6WMqLxtV15cCrBolXJstE+/L5xn0QCK
   318  OmAKnJ+D0TDa4mBh3qrDPFhQuYO976E=
   319  -----END EC PRIVATE KEY-----`,
   320  			},
   321  		},
   322  		{
   323  			name: "P521",
   324  			inputCA: CAType{
   325  				Cert: `-----BEGIN CERTIFICATE-----
   326  MIIB+zCCAV2gAwIBAgIURSKnoMtOKXQwAH6TTssIVC1WEb8wCgYIKoZIzj0EAwQw
   327  GDEWMBQGA1UEAwwNZ2F0ZWtlZXBlcl9jYTAeFw0xOTEwMTgyMDQwMDBaFw0yNDEw
   328  MTYyMDQwMDBaMBgxFjAUBgNVBAMMDWdhdGVrZWVwZXJfY2EwgZswEAYHKoZIzj0C
   329  AQYFK4EEACMDgYYABAHIz+N4TtGLUy+ihSZx2TvoG7b1ASHAOMEH8JnMrr2IdMje
   330  hVQNqOdnmJ6C/tdbi7NLBvxzDDYSI9BHturD/4p/fgCKjzFixj90JnzlYGtsncRS
   331  DrR3Nx6R0i7RPwh3tK1RlFA9boac9LV60kJLcEcACS9E+hPNu4nfkb3ueK6nOODQ
   332  d6NCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
   333  FBGPR7uAFAYIyDvkfCVIzNieIjxvMAoGCCqGSM49BAMEA4GLADCBhwJBXxJg9+J6
   334  26nxTy8JolxJjPCVQ2WE2jos3MwvL795Ho/srpp3rJbg5YZWqeYtedh8AIgqXs2j
   335  i0CIzyx4PoJgM+8CQgE1XRx4hZNZzZm3MrYQ7EN6P3wp79ILweUf+i+rIsxMgAnM
   336  CRSsrWg3vzGpLYyWQhPs/tecpeinjCbj39hcBmn4Cw==
   337  -----END CERTIFICATE-----`,
   338  				Key: `-----BEGIN EC PRIVATE KEY-----
   339  MIHcAgEBBEIB8MTQXMNcKsFWnJyRNNWMKMD4ATNIqP56fSMcDWkOCYJucQbTa/gc
   340  Wy/AKjsRKVXO6xJSenLlX4z26tl2rvnt2eGgBwYFK4EEACOhgYkDgYYABAHIz+N4
   341  TtGLUy+ihSZx2TvoG7b1ASHAOMEH8JnMrr2IdMjehVQNqOdnmJ6C/tdbi7NLBvxz
   342  DDYSI9BHturD/4p/fgCKjzFixj90JnzlYGtsncRSDrR3Nx6R0i7RPwh3tK1RlFA9
   343  boac9LV60kJLcEcACS9E+hPNu4nfkb3ueK6nOODQdw==
   344  -----END EC PRIVATE KEY-----`,
   345  			},
   346  		},
   347  	}
   348  	for _, tt := range tests {
   349  		t.Run(tt.name, func(t *testing.T) {
   350  			req := require.New(t)
   351  
   352  			block, _ := pem.Decode([]byte(tt.inputCA.Cert))
   353  			req.NotEqual(nil, block)
   354  			parsedCA, err := x509.ParseCertificate(block.Bytes)
   355  			req.NoError(err, "parse CA certificate")
   356  
   357  			req.True(parsedCA.IsCA, "generated CA must be a CA")
   358  
   359  			// test CA regeneration
   360  			renewCA, err := RenewCA(tt.inputCA)
   361  			req.NoError(err)
   362  
   363  			// validate regenerated CA is still valid
   364  			_, err = tls.X509KeyPair([]byte(renewCA.Cert), []byte(renewCA.Key))
   365  			req.NoError(err)
   366  			renewBlock, _ := pem.Decode([]byte(renewCA.Cert))
   367  			req.NotEqual(nil, renewBlock)
   368  			renewParsedCA, err := x509.ParseCertificate(renewBlock.Bytes)
   369  			req.NoError(err, "parse renewed CA certificate")
   370  
   371  			req.True(renewParsedCA.IsCA, "renewed CA must be a CA")
   372  
   373  			// new cert should not be the same as old cert
   374  			req.NotEqual(tt.inputCA.Cert, renewCA.Cert)
   375  			// new key should be the same as old key
   376  			req.Equal(tt.inputCA.Key, renewCA.Key)
   377  
   378  			// new CA must expire after old CA
   379  			req.True(renewParsedCA.NotAfter.After(parsedCA.NotAfter), "renewed CA must expire after original")
   380  		})
   381  	}
   382  }
   383  
   384  func TestMakeCert(t *testing.T) {
   385  	tests := []struct {
   386  		name     string
   387  		caKind   string
   388  		certKind string
   389  		hosts    []string
   390  	}{
   391  		{
   392  			name:     "empty kind",
   393  			caKind:   "",
   394  			certKind: "",
   395  			hosts:    []string{},
   396  		},
   397  		{
   398  			name:     "mixed rsa with hostnames",
   399  			caKind:   "rsa-4096",
   400  			certKind: "rsa-2048",
   401  			hosts:    []string{"example.com", "another.co", "1.2.3.4"},
   402  		},
   403  		{
   404  			name:     "P256",
   405  			caKind:   "P256",
   406  			certKind: "P256",
   407  		},
   408  		{
   409  			name:     "P384",
   410  			caKind:   "P384",
   411  			certKind: "P384",
   412  			hosts:    []string{"first.xyz", "subdomain.another.co", "4.3.2.1"},
   413  		},
   414  		{
   415  			name:     "P521",
   416  			caKind:   "P521",
   417  			certKind: "P521",
   418  		},
   419  	}
   420  	for _, tt := range tests {
   421  		t.Run(tt.name, func(t *testing.T) {
   422  			req := require.New(t)
   423  
   424  			ca, err := MakeCA(tt.caKind)
   425  			req.NoError(err)
   426  
   427  			// validate ca was generated properly
   428  			_, err = tls.X509KeyPair([]byte(ca.Cert), []byte(ca.Key))
   429  			req.NoError(err)
   430  
   431  			block, _ := pem.Decode([]byte(ca.Cert))
   432  			req.NotEqual(nil, block)
   433  			parsedCA, err := x509.ParseCertificate(block.Bytes)
   434  			req.NoError(err, "parse CA certificate")
   435  
   436  			req.True(parsedCA.IsCA, "generated CA must be a CA")
   437  
   438  			// make cert
   439  			cert, err := MakeCert(tt.hosts, tt.certKind, ca.Cert, ca.Key)
   440  			req.NoError(err)
   441  
   442  			// validate cert was generated properly
   443  			_, err = tls.X509KeyPair([]byte(cert.Cert), []byte(cert.Key))
   444  			req.NoError(err)
   445  
   446  			block, _ = pem.Decode([]byte(cert.Cert))
   447  			req.NotEqual(nil, block)
   448  			parsedCert, err := x509.ParseCertificate(block.Bytes)
   449  			req.NoError(err, "parse new cert")
   450  
   451  			req.False(parsedCert.IsCA, "generated cert must not be a CA")
   452  
   453  			err = parsedCert.CheckSignatureFrom(parsedCA)
   454  			req.NoError(err, "cert must be signed by CA")
   455  
   456  			for _, host := range tt.hosts {
   457  				err = parsedCert.VerifyHostname(host)
   458  				req.NoError(err, "hostname %s must be present on cert", host)
   459  			}
   460  
   461  			// validate that the cert is valid for two more years
   462  			req.True(parsedCert.NotAfter.Add(-time.Hour * (17520 - 1)).After(time.Now()))
   463  			// and that it is valid now
   464  			req.True(parsedCert.NotBefore.Before(time.Now()))
   465  		})
   466  	}
   467  }