Certificates.cpp (15469B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "TestCommon.h" 5 #include <winget/Certificates.h> 6 #include <CertificateResources.h> 7 8 using namespace TestCommon; 9 using namespace AppInstaller; 10 using namespace AppInstaller::Certificates; 11 12 13 TEST_CASE("Certificates_NoPinningSucceeds", "[certificates]") 14 { 15 PinningDetails expected; 16 expected.LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::None); 17 18 PinningDetails actual; 19 actual.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 20 21 REQUIRE(CertificatePinningValidationResult::Accepted == expected.Validate(actual.GetCertificate(), CertificateChainPosition::Leaf)); 22 } 23 24 TEST_CASE("Certificates_PublicKeyMismatch", "[certificates]") 25 { 26 PinningDetails expected; 27 expected.LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey); 28 29 PinningDetails actual; 30 actual.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 31 32 REQUIRE(CertificatePinningValidationResult::Rejected == expected.Validate(actual.GetCertificate(), CertificateChainPosition::Leaf)); 33 } 34 35 TEST_CASE("Certificates_PublicKeyMatch", "[certificates]") 36 { 37 PinningDetails expected; 38 expected.LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey); 39 40 PinningDetails actual; 41 actual.LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE); 42 43 REQUIRE(CertificatePinningValidationResult::Accepted == expected.Validate(actual.GetCertificate(), CertificateChainPosition::Root)); 44 } 45 46 TEST_CASE("Certificates_SubjectMismatch", "[certificates]") 47 { 48 PinningDetails expected; 49 expected.LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject); 50 51 PinningDetails actual; 52 actual.LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE); 53 54 REQUIRE(CertificatePinningValidationResult::Rejected == expected.Validate(actual.GetCertificate(), CertificateChainPosition::Intermediate)); 55 } 56 57 TEST_CASE("Certificates_SubjectMatch", "[certificates]") 58 { 59 PinningDetails expected; 60 expected.LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject); 61 62 PinningDetails actual; 63 actual.LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE); 64 65 REQUIRE(CertificatePinningValidationResult::Accepted == expected.Validate(actual.GetCertificate(), CertificateChainPosition::Intermediate)); 66 } 67 68 TEST_CASE("Certificates_IssuerMismatch", "[certificates]") 69 { 70 PinningDetails expected; 71 expected.LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Issuer); 72 73 PinningDetails actual; 74 actual.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 75 76 REQUIRE(CertificatePinningValidationResult::Rejected == expected.Validate(actual.GetCertificate(), CertificateChainPosition::Leaf)); 77 } 78 79 TEST_CASE("Certificates_IssuerMatch", "[certificates]") 80 { 81 PinningDetails expected; 82 expected.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Issuer); 83 84 PinningDetails actual; 85 actual.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 86 87 REQUIRE(CertificatePinningValidationResult::Accepted == expected.Validate(actual.GetCertificate(), CertificateChainPosition::Leaf)); 88 } 89 90 TEST_CASE("Certificates_ChainLengthDiffers", "[certificates]") 91 { 92 PinningChain chain; 93 auto chainElement = chain.Root(); 94 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey); 95 chainElement = chainElement.Next(); 96 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 97 98 PinningConfiguration config; 99 config.AddChain(chain); 100 101 PinningDetails details; 102 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 103 104 REQUIRE(!config.Validate(details.GetCertificate())); 105 } 106 107 TEST_CASE("Certificates_ChainLengthDiffers_Partial", "[certificates]") 108 { 109 PinningChain chain; 110 auto chainElement = chain.Root(); 111 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey); 112 chainElement = chainElement.Next(); 113 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 114 chain.PartialChain(); 115 116 PinningConfiguration config; 117 config.AddChain(chain); 118 119 PinningDetails details; 120 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 121 122 REQUIRE(config.Validate(details.GetCertificate())); 123 } 124 125 TEST_CASE("CertificateChain_AnyIssuer_Intermediate", "[certificates]") 126 { 127 PinningChain chain; 128 auto chainElement = chain.Root(); 129 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey | PinningVerificationType::AnyIssuer | PinningVerificationType::RequireNonLeaf); 130 chain.PartialChain(); 131 132 PinningConfiguration config; 133 config.AddChain(chain); 134 135 PinningDetails details; 136 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 137 138 REQUIRE(config.Validate(details.GetCertificate())); 139 } 140 141 TEST_CASE("CertificateChain_AnyIssuer_IntermediateDiffers", "[certificates]") 142 { 143 PinningChain chain; 144 auto chainElement = chain.Root(); 145 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_1, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey | PinningVerificationType::AnyIssuer | PinningVerificationType::RequireNonLeaf); 146 chain.PartialChain(); 147 148 PinningConfiguration config; 149 config.AddChain(chain); 150 151 PinningDetails details; 152 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 153 154 REQUIRE(!config.Validate(details.GetCertificate())); 155 } 156 157 TEST_CASE("CertificateChain_AnyIssuer_IntermediateAndLeaf", "[certificates]") 158 { 159 PinningChain chain; 160 auto chainElement = chain.Root(); 161 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey | PinningVerificationType::AnyIssuer | PinningVerificationType::RequireNonLeaf); 162 chainElement = chainElement.Next(); 163 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 164 chain.PartialChain(); 165 166 PinningConfiguration config; 167 config.AddChain(chain); 168 169 PinningDetails details; 170 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 171 172 REQUIRE(config.Validate(details.GetCertificate())); 173 } 174 175 TEST_CASE("CertificateChain_AnyIssuer_Leaf", "[certificates]") 176 { 177 PinningChain chain; 178 auto chainElement = chain.Root(); 179 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey | PinningVerificationType::AnyIssuer); 180 chain.PartialChain(); 181 182 PinningConfiguration config; 183 config.AddChain(chain); 184 185 PinningDetails details; 186 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 187 188 REQUIRE(config.Validate(details.GetCertificate())); 189 } 190 191 TEST_CASE("CertificateChain_AnyIssuer_LeafDiffers", "[certificates]") 192 { 193 PinningChain chain; 194 auto chainElement = chain.Root(); 195 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_1, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey | PinningVerificationType::AnyIssuer); 196 chain.PartialChain(); 197 198 PinningConfiguration config; 199 config.AddChain(chain); 200 201 PinningDetails details; 202 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 203 204 REQUIRE(!config.Validate(details.GetCertificate())); 205 } 206 207 TEST_CASE("CertificateChain_AnyIssuer_SameLeaf_RequireNonLeaf", "[certificates]") 208 { 209 PinningChain chain; 210 auto chainElement = chain.Root(); 211 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey | PinningVerificationType::AnyIssuer | PinningVerificationType::RequireNonLeaf); 212 chain.PartialChain(); 213 214 PinningConfiguration config; 215 config.AddChain(chain); 216 217 PinningDetails details; 218 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 219 220 REQUIRE(!config.Validate(details.GetCertificate())); 221 } 222 223 TEST_CASE("Certificates_EmptyChainRejects", "[certificates]") 224 { 225 PinningChain chain; 226 227 PinningConfiguration config; 228 config.AddChain(chain); 229 230 PinningDetails details; 231 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 232 233 REQUIRE(!config.Validate(details.GetCertificate())); 234 } 235 236 TEST_CASE("Certificates_ChainOrderDiffers", "[certificates]") 237 { 238 PinningChain chain; 239 auto chainElement = chain.Root(); 240 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey); 241 chainElement = chainElement.Next(); 242 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 243 chainElement = chainElement.Next(); 244 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 245 246 PinningConfiguration config; 247 config.AddChain(chain); 248 249 PinningDetails details; 250 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 251 252 REQUIRE(!config.Validate(details.GetCertificate())); 253 } 254 255 TEST_CASE("Certificates_StoreChain_BuiltInTest", "[certificates]") 256 { 257 PinningChain chain; 258 auto chainElement = chain.Root(); 259 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey); 260 chainElement = chainElement.Next(); 261 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 262 chainElement = chainElement.Next(); 263 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 264 265 PinningConfiguration config; 266 config.AddChain(chain); 267 268 PinningDetails details; 269 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 270 271 REQUIRE(config.Validate(details.GetCertificate())); 272 } 273 274 TEST_CASE("Certificates_MultipleChains_Success", "[certificates]") 275 { 276 PinningChain chainOutOfOrder; 277 auto chainElement = chainOutOfOrder.Root(); 278 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey); 279 chainElement = chainElement.Next(); 280 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 281 chainElement = chainElement.Next(); 282 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 283 284 PinningConfiguration config; 285 config.AddChain(chainOutOfOrder); 286 287 PinningChain chain; 288 chainElement = chain.Root(); 289 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::PublicKey); 290 chainElement = chainElement.Next(); 291 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 292 chainElement = chainElement.Next(); 293 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetPinning(PinningVerificationType::Subject | PinningVerificationType::Issuer); 294 295 config.AddChain(chain); 296 297 PinningDetails details; 298 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 299 300 REQUIRE(config.Validate(details.GetCertificate())); 301 } 302 303 TEST_CASE("CertificateChain_Position", "[certificates]") 304 { 305 CertificateChainPosition positions[3]{ CertificateChainPosition::Unknown, CertificateChainPosition::Unknown, CertificateChainPosition::Unknown }; 306 307 PinningChain chain; 308 auto chainElement = chain.Root(); 309 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetCustomValidationFunction([&](const PinningDetails&, PCCERT_CONTEXT, CertificateChainPosition position) { positions[0] = position; return true; }); 310 chainElement = chainElement.Next(); 311 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_INTERMEDIATE_2, CERTIFICATE_RESOURCE_TYPE).SetCustomValidationFunction([&](const PinningDetails&, PCCERT_CONTEXT, CertificateChainPosition position) { positions[1] = position; return true; }); 312 chainElement = chainElement.Next(); 313 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE).SetCustomValidationFunction([&](const PinningDetails&, PCCERT_CONTEXT, CertificateChainPosition position) { positions[2] = position; return true; }); 314 315 PinningConfiguration config; 316 config.AddChain(chain); 317 318 PinningDetails details; 319 details.LoadCertificate(IDX_CERTIFICATE_STORE_LEAF_2, CERTIFICATE_RESOURCE_TYPE); 320 321 REQUIRE(config.Validate(details.GetCertificate())); 322 323 REQUIRE(CertificateChainPosition::Root == positions[0]); 324 REQUIRE(CertificateChainPosition::Intermediate == positions[1]); 325 REQUIRE(CertificateChainPosition::Leaf == positions[2]); 326 } 327 328 TEST_CASE("CertificateChain_Position_SelfSigned", "[certificates]") 329 { 330 CertificateChainPosition positions[1]{ CertificateChainPosition::Unknown }; 331 332 PinningChain chain; 333 auto chainElement = chain.Root(); 334 chainElement->LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE).SetCustomValidationFunction([&](const PinningDetails&, PCCERT_CONTEXT, CertificateChainPosition position) { positions[0] = position; return true; }); 335 336 PinningConfiguration config; 337 config.AddChain(chain); 338 339 PinningDetails details; 340 details.LoadCertificate(IDX_CERTIFICATE_STORE_ROOT_2, CERTIFICATE_RESOURCE_TYPE); 341 342 REQUIRE(config.Validate(details.GetCertificate())); 343 344 REQUIRE((CertificateChainPosition::Root | CertificateChainPosition::Leaf) == positions[0]); 345 }