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 MIIJJwIBAAKCAgEArPR/QLRJ/YE5FT6/WnvhtA443lhJ7I0MGVQimMSF0WJd2fKS 228 yZYLgcd83e5tCUgF38JurAKxwPCla/G1CmMKNLvGlsqjAnc0DGVhp7VScyVdip7Z 229 /fgLqnDCgcsPWD1zp62XdnOt2W5OeFr3rlAZ8xMyOR39FfhAq5QHNSVpZwSW7NuP 230 GawiwA3D0Qko4SvXuT+zqTSO4Xz6NAnBI05hAyb9EHafOVb9euW93SQtDCAryjnT 231 7dXtCUOmHNmtSHE1ToJhp3Hk7iponKpYe1hLzXkjgy4bpXeXGezFofqZuBlgouSf 232 7ZIiXWt8yif2iZOJ9RSnXMC3cXdZHHU56H/8ibeKR6pAVXVmCEbc05x02U1Blnez 233 KyXi38XSY2cjokUBsac0pgTtUdDqMNIjrhGKm+mH6tfGniYatrSUuI8jQJxD5hqH 234 2U/9cy/i1trdpfoR6QVeBj9JgJDmwZDWRVmlMKGZr8EQix5qblNzYJghj1z2x3m9 235 jgcgQ9sYp55f/6I7NUHzm7WoEh6TKbr0qY3kERN0NLw6ePcEsZRFxInCLGl2TXx4 236 60n7E5tq7QzFERwJrVm3uJFUACVnvuPBjr/Bu3k0O9k1AIO4lukRU6VHBKYrYReS 237 wRSngFHfATsU+jR+BQ2z7SIkQEh2xTA5q7NQGUIAdDd3OZNzmxnqmxWgkfsCAwEA 238 AQKCAgAbNAmf37uTh/O2h7wJO1rwuxvuvOxDrJuukDEw3hg+Kr6gPSshUdxVeU8G 239 iS3VO+LQowBNRc83jaI3LDlRfOpqCO7fYNfq11z0Zi3J9xcUzVe9KecXryAGmt29 240 FHdBZcj/IqqkEuXRQSxOeeBjJm4ucWKA4VqhTf69/fZ0QYImle43KwGDBDQjCQc3 241 pb0sTX0Mwhw8DOw8QzAHZ1FdgEJ6AHPlVwMMPcZ4whHu6nW7ZoP8tsPCsNcrkdxa 242 xVIgBs5fntpFQADGBR2XJqPsIqMpmlgflez7Ragah8c+BvCOqE8uz87nywhksTdb 243 hJWeZfpY9fqs+BLiYec+NqH5E8hgjqlzw9hFcKORwHVQx4LjPHATbVk40ctIPpwT 244 nSlTEKtIvQJcjxJwrm/HDbgRqtgNODJaKh2zMDQqbNyEwgH88ncLVTTNz5W7XntE 245 XFWBfqte+KVscbvKDdMFs32237hhEz8uZQqhLkXBYyRv6as6VGb3T/6If8QNgC9o 246 TNmB9eNCKmuLdhSZpO1LdckrLm2R0XWFSeAyvT0Xy7ajKq16gH0PwdTXc7iZKq7U 247 biSCly9GO62zUDQ5ad5t1Sc6SbZPQh4cFhEyytIGsN9IdBoq9ySEuaI6pgp2A0Mv 248 if/2k2PzJJ5MJVyuMHE0GMqN8VzSPT8ic/2/ZgO2DfKv2sVyYQKCAQEA2IvYyHIN 249 plM4PUiizZyJOWU2/qrPOYzuW1nuD1gP6CX17LtG5xQRXTOlFIIkEnXNDfYLOA9y 250 LEbD5n0GOxa8lhEXx4LI4RaKcIMWZ77EtT/0e5/1ZeiqXcMoYXv705swmBSVCPz7 251 XyT9oc+Y1vpZ6VkFmzKhRGBnXWTTuhSx1io8lXHjEwZVyKoATfluVztG0tRb08E8 252 DqRiHBzgF300padbjj0T50mcyxqVyiTwbqvN3ihipWDLh+7kQ+Gv/XWvdyauBgXd 253 U+fgOLh7s0WGIPCWLliQuD93fux+UacdlQnot3geuP/ANgFfIevvqMQi7hODOBcL 254 QM2yo/As5P6HlQKCAQEAzHd3/TkKGI9s5STmFWKGu0Qv2ngplQNXMVeFgTJiIhcB 255 KPaAXCjtx3IQOTtutG8bV/RcSMvNW0v8UPMyz9uqjpfKWC6c5AkbtC601jdFspHX 256 CJcY6qhd9TkqwWXAf2bdFCSaqfHUd986O61wlKuHtu/RyiHPf2INdbuQbu2n0IGf 257 OdNVDlCuSmnlss1P4uWUiJAuwMzEkicp/4AKqOP7fa9ZRaNr4qRtsThr/4wkXEI4 258 ne7tEgJD3I6d8B15m3Ct7BCULaa4yvbsD90IVt7Y/KZIOZ6dbg+4N1nBd3+Hs/RL 259 zrKZLDn4DB2q8tHjezq2M7SGB52wETR1rnwGV9cPTwKCAQB7VqwS/2Nm6N+PiF+y 260 XQaL+mpog0GktfDNd1twwefNglGglMq9s2BwhYnxNG73VMGGwi2BsMqHDYdnMK7r 261 2PdxQisZKBTin8QacY/BZ5cC5XqLL4DGms7uuMm3PLciv7Hd7Vs102IZvyf3khar 262 28x6bIoU67GPEJnPSC6QPllMcqIvPL7phyI1OR8TSo7egJTGYM4svlNGw7pd6NR6 263 jIYAFGLBkWhUxEjaJjpK+N85KgIIF1iYeZlzw02gnFtxMibO5ukX5R87O0crB2jt 264 oxvShzYDD87eIsgdMvZ/63+d9Bbo6TIWjRUdrYpR9+B5b721fMewmu996atmVNY9 265 V/xBAoIBAHZWJqHt40P3roSoaGm0DlpPyopcxWQy/MHX77KooFcujUNR91Rfc87c 266 2zrkhNv0+hRbnxWaro3KWovXVW8rqXjBrSCASdlI1DniVlMsxi/lbFjSal9Vdpu4 267 rGAmLdUOiaFg1grJpbiC/8cOSHwjEnb0Ma0VCGynKTcciSlKbrekba0f/Lg+RcFX 268 rNNhNH0TdnXbTNPVL2ePNyViy8iXujQxyi8duBECLWJGT2slht3GjdIKODcWDISY 269 HhycUod+HYrkxX3uYkFFy7YarPrqGxeOfXqrrF3Ix0txrSEmNDoYh89nWnNYUZFh 270 klDa3RezEUS3lGLQBtjOTdXgfiNUms0CggEANiDErC4EYALXTA0LtUl5IQwu8FYi 271 02WIIzObbuyORPtdvhhO6W6KxxEGIsyxleNRpbOMje+6+diWb1o6NCmJLcU1Zv9N 272 lbpDHyJj5c7ShrN8Ug0igDS9ZFED8YT63FbVQnkNb/3CXuO3FeIzDeQ4iaECo1i0 273 0ztD0gY9jS6OrZRZFyRel1GowcvHPdkvV1wQWLZGvqUmhC802JUmq3NmeqfRqIDZ 274 SOjE3BVb+saqb5jSP0rEgXienjJF0syS9Csft14+7tibQCOfg82OrNfz5mi7iDxJ 275 V4Lx0AIJKYQcRbMrf92OHZniggpMKWEbyrvc0XxN7qNR7xPv0r7k8FcPCw== 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 }