istio.io/istio@v0.0.0-20240520182934-d79c90f27776/security/pkg/pki/util/verify_cert_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package util 16 17 import ( 18 "crypto/x509" 19 "log" 20 "os" 21 "strings" 22 "testing" 23 "time" 24 ) 25 26 func loadPEMFile(path string) string { 27 b, err := os.ReadFile(path) 28 if err != nil { 29 log.Fatalf("failed to load the pem file = %v, err = %v", path, err) 30 } 31 return string(b) 32 } 33 34 var ( 35 key = loadPEMFile("../testdata/key-10y.pem") 36 keyMismatch = loadPEMFile("../testdata/key-mismatch.pem") 37 keyBad = loadPEMFile("../testdata/key-verify-fail.pem") 38 certChainBad = loadPEMFile("../testdata/cert-verify-fail.pem") 39 certChainNoRoot = loadPEMFile("../testdata/cert-noroot.pem") 40 certChain = loadPEMFile("../testdata/cert-chain-10y.pem") 41 rootCertBad = loadPEMFile("../testdata/root-verify-fail.pem") 42 rootCert = loadPEMFile("../testdata/root-cert-10y.pem") 43 verifyField1 = &VerifyFields{ 44 Host: "", 45 } 46 47 verifyField2 = &VerifyFields{ 48 Host: "spiffe", 49 } 50 51 notBefore = &VerifyFields{ 52 NotBefore: time.Unix(0, 0), 53 Host: "spiffe://cluster.local/ns/default/sa/default", 54 } 55 56 ttl = &VerifyFields{ 57 TTL: time.Duration(0), 58 Host: "spiffe://cluster.local/ns/default/sa/default", 59 } 60 61 extKeyUsage = &VerifyFields{ 62 TTL: time.Duration(1), 63 Host: "spiffe://cluster.local/ns/default/sa/default", 64 } 65 66 keyUsage = &VerifyFields{ 67 ExtKeyUsage: []x509.ExtKeyUsage{1, 2}, 68 KeyUsage: 2, 69 Host: "spiffe://cluster.local/ns/default/sa/default", 70 } 71 72 isCA = &VerifyFields{ 73 ExtKeyUsage: []x509.ExtKeyUsage{1, 2}, 74 KeyUsage: 5, 75 IsCA: true, 76 Host: "spiffe://cluster.local/ns/default/sa/default", 77 } 78 79 org = &VerifyFields{ 80 ExtKeyUsage: []x509.ExtKeyUsage{1, 2}, 81 KeyUsage: 5, 82 Org: "bad", 83 Host: "spiffe://cluster.local/ns/default/sa/default", 84 } 85 86 success = &VerifyFields{ 87 ExtKeyUsage: []x509.ExtKeyUsage{1, 2}, 88 KeyUsage: 5, 89 Host: "spiffe://cluster.local/ns/default/sa/default", 90 } 91 ) 92 93 func TestVerifyCert(t *testing.T) { 94 testCases := map[string]struct { 95 privPem []byte 96 certChainPem []byte 97 rootCertPem []byte 98 expectedFields *VerifyFields 99 expectedErr string 100 }{ 101 "Root cert bad": { 102 privPem: nil, 103 certChainPem: nil, 104 rootCertPem: []byte(rootCertBad), 105 expectedFields: verifyField1, 106 expectedErr: "failed to parse root certificate", 107 }, 108 "Cert chain bad": { 109 privPem: nil, 110 certChainPem: []byte(certChainBad), 111 rootCertPem: []byte(rootCert), 112 expectedFields: verifyField1, 113 expectedErr: "failed to parse certificate chain", 114 }, 115 "Failed to verify cert chain": { 116 privPem: nil, 117 certChainPem: []byte(certChainNoRoot), 118 rootCertPem: []byte(rootCert), 119 expectedFields: verifyField2, 120 expectedErr: "failed to verify certificate: x509:", 121 }, 122 "Failed to verify key": { 123 privPem: []byte(keyBad), 124 certChainPem: []byte(certChain), 125 rootCertPem: []byte(rootCert), 126 expectedFields: verifyField2, 127 expectedErr: "invalid PEM-encoded key", 128 }, 129 "Failed to match key/cert": { 130 privPem: []byte(keyMismatch), 131 certChainPem: []byte(certChain), 132 rootCertPem: []byte(rootCert), 133 expectedFields: verifyField2, 134 expectedErr: "the generated private RSA key and cert doesn't match", 135 }, 136 "Wrong SAN": { 137 privPem: []byte(key), 138 certChainPem: []byte(certChain), 139 rootCertPem: []byte(rootCert), 140 expectedFields: verifyField2, 141 expectedErr: "the certificate doesn't have the expected SAN for: spiffe", 142 }, 143 "Timestamp error": { 144 privPem: []byte(key), 145 certChainPem: []byte(certChain), 146 rootCertPem: []byte(rootCert), 147 expectedFields: notBefore, 148 expectedErr: "unexpected value for 'NotBefore' field", 149 }, 150 "TTL error": { 151 privPem: []byte(key), 152 certChainPem: []byte(certChain), 153 rootCertPem: []byte(rootCert), 154 expectedFields: extKeyUsage, 155 expectedErr: "unexpected value for 'NotAfter' - 'NotBefore'", 156 }, 157 "extKeyUsage error": { 158 privPem: []byte(key), 159 certChainPem: []byte(certChain), 160 rootCertPem: []byte(rootCert), 161 expectedFields: ttl, 162 expectedErr: "unexpected value for 'ExtKeyUsage' field", 163 }, 164 "KeyUsage Error": { 165 privPem: []byte(key), 166 certChainPem: []byte(certChain), 167 rootCertPem: []byte(rootCert), 168 expectedFields: keyUsage, 169 expectedErr: "unexpected value for 'KeyUsage' field", 170 }, 171 "IsCA error": { 172 privPem: []byte(key), 173 certChainPem: []byte(certChain), 174 rootCertPem: []byte(rootCert), 175 expectedFields: isCA, 176 expectedErr: "unexpected value for 'IsCA' field", 177 }, 178 "Org error": { 179 privPem: []byte(key), 180 certChainPem: []byte(certChain), 181 rootCertPem: []byte(rootCert), 182 expectedFields: org, 183 expectedErr: "unexpected value for 'Organization' field", 184 }, 185 "Succeeded": { 186 privPem: []byte(key), 187 certChainPem: []byte(certChain), 188 rootCertPem: []byte(rootCert), 189 expectedFields: success, 190 expectedErr: "", 191 }, 192 } 193 for id, tc := range testCases { 194 err := VerifyCertificate( 195 tc.privPem, tc.certChainPem, tc.rootCertPem, tc.expectedFields) 196 if err != nil { 197 if len(tc.expectedErr) == 0 { 198 t.Errorf("%s: Unexpected error: %v", id, err) 199 } else if !strings.Contains(err.Error(), tc.expectedErr) { 200 t.Errorf("%s: Unexpected error: %v VS (expected) %s", id, err, tc.expectedErr) 201 } 202 } else if len(tc.expectedErr) != 0 { 203 t.Errorf("%s: Expected error %s but succeeded", id, tc.expectedErr) 204 } 205 } 206 } 207 208 func TestCertExpired(t *testing.T) { 209 testCases := map[string]struct { 210 filepath string 211 expected bool 212 }{ 213 "Expired Cert": { 214 filepath: "../testdata/expired-cert.pem", 215 expected: true, 216 }, 217 "Not Expired Cert": { 218 filepath: "../testdata/notexpired-cert.pem", 219 expected: false, 220 }, 221 } 222 for id, tc := range testCases { 223 t.Run(id, func(t *testing.T) { 224 certExpired, err := IsCertExpired(tc.filepath) 225 if err != nil { 226 t.Fatalf("failed to check the cert, err is: %v", err) 227 } 228 if certExpired != tc.expected { 229 t.Errorf("isCertExpired: get %v, want %v", certExpired, tc.expected) 230 } 231 }) 232 } 233 }