1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCertificates open source project
//
// Copyright (c) 2022 Apple Inc. and the SwiftCertificates project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftCertificates project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import Foundation
import XCTest
import SwiftASN1
@testable import X509
import Crypto
import _CryptoExtras
final class CertificateDERTests: XCTestCase {
static let base64EncodedSampleCert = """
MIIDsjCCAzigAwIBAgIQDKuq0c7E6XzCZliB0CE49zAKBggqhkjOPQQDAzBhMQsw
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe
Fw0yMDA0MjkxMjM0NTJaFw0zMDA0MTAyMzU5NTlaMFExCzAJBgNVBAYTAlVTMRMw
EQYDVQQKEwpBcHBsZSBJbmMuMS0wKwYDVQQDEyRBcHBsZSBQdWJsaWMgRVYgU2Vy
dmVyIEVDQyBDQSAxIC0gRzEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQp+OFa
uYdEBJj/FpCG+eDhQmVfhv0DGPzGz40TW8BeWxipYTOa4FLieAYoU+3t2tg9FZKt
A4BDTO43YprLZm6zo4IB4DCCAdwwHQYDVR0OBBYEFOCFSH0TptMQGZ9cy2t4JJL4
rhuuMB8GA1UdIwQYMBaAFLPbSKT5ocXYrjZBzBFjaWIpvEvGMA4GA1UdDwEB/wQE
AwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgw
BgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw
LmRpZ2ljZXJ0LmNvbTBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdp
Y2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290RzMuY3JsMIHcBgNVHSAEgdQwgdEw
gcUGCWCGSAGG/WwCATCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl
cnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRp
ZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFy
dHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t
L3JwYS11YTAHBgVngQwBATAKBggqhkjOPQQDAwNoADBlAjEAyHLAT/4iBuxi4/NH
hZde4PZO8CnG2/A3oGO0Nsjpoe2SV94Hr+JpYHrBzT8hyeKSAjBnRXyRac9sM8KN
Fdg3+7LWIiW9sUjtJC6kGmRyGm6vV4oAhEDd9jdk4q+7b5zlid4=
"""
static let base64EncodedRSARootCert = """
MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
NVOFBkpdn627G190
"""
/// A Safari codesign chain
static let codesignCerts = [
"""
MIIEtDCCA5ygAwIBAgIIZO/q/sI56KUwDQYJKoZIhvcNAQEFBQAwfzELMAkGA1UE
BhMCVVMxEzARBgNVBAoMCkFwcGxlIEluYy4xJjAkBgNVBAsMHUFwcGxlIENlcnRp
ZmljYXRpb24gQXV0aG9yaXR5MTMwMQYDVQQDDCpBcHBsZSBDb2RlIFNpZ25pbmcg
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAxMDI5MTgzMjM4WhcNMjYxMDI0
MTczOTQxWjBWMQswCQYDVQQGEwJVUzETMBEGA1UECgwKQXBwbGUgSW5jLjEXMBUG
A1UECwwOQXBwbGUgU29mdHdhcmUxGTAXBgNVBAMMEFNvZnR3YXJlIFNpZ25pbmcw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/MLh0mE+uBguklG4xVG0J
0TyjsDkQqdDmqmAiXdPkhKJAQZBkxmA9kWHaUqhFJ54sZMvkHqgkClI6s9PsFkF4
wZ7RBuZ4JWMI89/KQeYd/jXpUVwTFYvp0Z1xe9HJqkuemdqPwCm4L5BvpLtlj4Bq
1z1obeR4wqUSL/gy6X7JXVyMPhYgG9denRuGLQj3vBmkTQ5BpErbaxqARVAEqUyN
FQfqaie9u4iePD+yUjmX47fI61RSmIovI1Zl5ekq2VG0I/oE3ffroN/VmvJeCPFf
h/CxR2x1sbGM0RPjesHsYkF0poM08fladGQ5P1luzyzAYIMpPOfeT18N85M5XzCN
AgMBAAGjggFbMIIBVzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFI5ppsR3Qk4E
pVZCnFEfhtrSII8JMIGWBgNVHSAEgY4wgYswgYgGCSqGSIb3Y2QFATB7MHkGCCsG
AQUFBwICMG0Ma1RoaXMgY2VydGlmaWNhdGUgaXMgdG8gYmUgdXNlZCBleGNsdXNp
dmVseSBmb3IgZnVuY3Rpb25zIGludGVybmFsIHRvIEFwcGxlIFByb2R1Y3RzIGFu
ZC9vciBBcHBsZSBwcm9jZXNzZXMuMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMDUG
A1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwuYXBwbGUuY29tL2NvZGVzaWduaW5n
LmNybDAdBgNVHQ4EFgQUxu0+Svsu6D8T1aAVs13Z57P3aDUwDgYDVR0PAQH/BAQD
AgeAMA8GCSqGSIb3Y2QGFgQCBQAwDQYJKoZIhvcNAQEFBQADggEBAImdqA6ANj/n
AWa6c4Ijc5udq8taXsIwT5AlYJpJMQQJUja4xm5KZlc/Vazm9eTSdfdbz2WD+yj5
lWkQSsmpwpz+iyAgipl+m2JBmp+mh7pI9nGwlYwkAgg/PrkW8D74/mf+9tidOr6Q
wQLQSb+bzRoRGQAFOoAVTX0s4419xIygW2SwzhBvXDW5XhZPy/IdTtej2tN9ovsY
gOBfN9okEUUes4byotjYEeFMNJSWlchRoQhYM2BvvL3PjFYzdUgS5OZrTZjrVDE1
8DlIa8DPVeqoeE7C699Yb8dRF9XYVUG8aVXco7QB9N80o0zagpmAQtoHMos3u8rh
59zvNaFyVtE=
""",
"""
MIIEDjCCAvagAwIBAgIBITANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET
MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMTExMDI0MTcz
OTQxWhcNMjYxMDI0MTczOTQxWjB/MQswCQYDVQQGEwJVUzETMBEGA1UECgwKQXBw
bGUgSW5jLjEmMCQGA1UECwwdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
MzAxBgNVBAMMKkFwcGxlIENvZGUgU2lnbmluZyBDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKKoEXH/DvkLa/gl
DZiBXWtZvVobibPn5e7OOZgjNTlInyGrJ9nunCDwZDgIawynz9xQth0GxFvxXRqb
VGWGcy9i5Ti9ARBkcm18aUdhnBAFJuPrhcIsJNxqwj+I/MysKUyhSXkRmnV25R64
0NIJtExTePvfGHahj6SpMsqRp7b6l705qs0bUBGIq2rt62bKIEusOy3vqufWyYgt
acKkKmEv24cC86EhuUyfDvj52S3KcgR/Ha5u+j+Is8yjQO4XhxhRlrzP5C2twulZ
Tl0cZTMnA6pno5Mkh8eHeQK5XZizDu7NaQg+jEiSJLJt1zC+z9jkyKeXgdAeI9w4
mV9h/oUCAwEAAaOBsTCBrjAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYB
BQUHAwMwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjmmmxHdCTgSlVkKcUR+G
2tIgjwkwHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wNgYDVR0fBC8w
LTAroCmgJ4YlaHR0cDovL3d3dy5hcHBsZS5jb20vYXBwbGVjYS9yb290LmNybDAN
BgkqhkiG9w0BAQUFAAOCAQEAcHOt9lIVarcVGN6pKtGddpsesmmWx8LD4SvQ7wdd
cPjaPFpIR9s5bIDKc95iG7c6yqNaHuOH2iVKk5vvcxCTc13j9J1+3g+B9qmZwVhu
nPSJAL7PT/8C0w789fP0choysconDt6o05mPauaZ+2HJT/IXsRhn8DDAxgruyESB
pIm78XlBw+6uyGtnfMxsSYZMAtPTam4YnPhcOMgwh5ow2mcouOKaedqfpTsfUWI7
IvF+U3waC8PwTdxJRPKIiM46W7md6bK3W1KnxtVYiXK32MyzqBgdUJc/Hdpqrji/
e3kxvmO594WFF+ltisTiGJQv129SpZmx3USbB3CSiCZ32w==
""",
"""
MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET
MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0
MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw
bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+
+FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1
XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w
tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW
q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM
aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3
R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE
ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93
d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl
IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0
YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj
b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp
Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc
NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP
y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7
R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg
xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP
IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX
UKqK1drk/NAJBzewdXUh
""",
]
func testSimpleDecode() throws {
let binary = Array(Data(base64Encoded: Self.base64EncodedSampleCert, options: .ignoreUnknownCharacters)!)
let cert = try Certificate(derEncoded: binary)
let expectedPublicKey = try P256.Signing.PublicKey(
x963Representation: [
0x04, 0x29, 0xf8, 0xe1, 0x5a, 0xb9, 0x87, 0x44, 0x04, 0x98, 0xff, 0x16, 0x90, 0x86, 0xf9,
0xe0, 0xe1, 0x42, 0x65, 0x5f, 0x86, 0xfd, 0x03, 0x18, 0xfc, 0xc6, 0xcf, 0x8d, 0x13, 0x5b,
0xc0, 0x5e, 0x5b, 0x18, 0xa9, 0x61, 0x33, 0x9a, 0xe0, 0x52, 0xe2, 0x78, 0x06, 0x28, 0x53,
0xed, 0xed, 0xda, 0xd8, 0x3d, 0x15, 0x92, 0xad, 0x03, 0x80, 0x43, 0x4c, 0xee, 0x37, 0x62,
0x9a, 0xcb, 0x66, 0x6e, 0xb3,
]
)
XCTAssertEqual(cert.version, .v3)
XCTAssertEqual(
cert.serialNumber.bytes,
[0x0c, 0xab, 0xaa, 0xd1, 0xce, 0xc4, 0xe9, 0x7c, 0xc2, 0x66, 0x58, 0x81, 0xd0, 0x21, 0x38, 0xf7]
)
XCTAssertEqual(cert.publicKey, Certificate.PublicKey(expectedPublicKey))
let expectedNotBefore = Date(timeIntervalSince1970: 1588163692.0)
let expectedNotAfter = Date(timeIntervalSince1970: 1902095999.0)
XCTAssertEqual(expectedNotBefore, cert.notValidBefore)
XCTAssertEqual(expectedNotAfter, cert.notValidAfter)
let expectedIssuer = try DistinguishedName([
RelativeDistinguishedName.Attribute(type: .RDNAttributeType.countryName, printableString: "US"),
RelativeDistinguishedName.Attribute(
type: .RDNAttributeType.organizationName,
printableString: "DigiCert Inc"
),
RelativeDistinguishedName.Attribute(
type: .RDNAttributeType.organizationalUnitName,
printableString: "www.digicert.com"
),
RelativeDistinguishedName.Attribute(
type: .RDNAttributeType.commonName,
printableString: "DigiCert Global Root G3"
),
])
let expectedSubject = try DistinguishedName([
RelativeDistinguishedName.Attribute(type: .RDNAttributeType.countryName, printableString: "US"),
RelativeDistinguishedName.Attribute(
type: .RDNAttributeType.organizationName,
printableString: "Apple Inc."
),
RelativeDistinguishedName.Attribute(
type: .RDNAttributeType.commonName,
printableString: "Apple Public EV Server ECC CA 1 - G1"
),
])
XCTAssertEqual(cert.issuer, expectedIssuer)
XCTAssertEqual(cert.subject, expectedSubject)
XCTAssertEqual(cert.extensions.count, 8)
XCTAssertEqual(
try cert.extensions.authorityInformationAccess,
.init([.init(method: .ocspServer, location: .uniformResourceIdentifier("http://ocsp.digicert.com"))])
)
XCTAssertEqual(
try cert.extensions.subjectKeyIdentifier,
.init(keyIdentifier: [
0xE0, 0x85, 0x48, 0x7D, 0x13, 0xA6, 0xD3, 0x10, 0x19, 0x9F, 0x5C, 0xCB, 0x6B, 0x78, 0x24, 0x92, 0xF8,
0xAE, 0x1B, 0xAE,
])
)
XCTAssertEqual(
try cert.extensions.authorityKeyIdentifier,
.init(keyIdentifier: [
0xB3, 0xDB, 0x48, 0xA4, 0xF9, 0xA1, 0xC5, 0xD8, 0xAE, 0x36, 0x41, 0xCC, 0x11, 0x63, 0x69, 0x62, 0x29,
0xBC, 0x4B, 0xC6,
])
)
XCTAssertEqual(
try cert.extensions.extendedKeyUsage,
try .init([.serverAuth, .clientAuth])
)
XCTAssertEqual(
try cert.extensions.basicConstraints,
.isCertificateAuthority(maxPathLength: 0)
)
XCTAssertEqual(
try cert.extensions.keyUsage,
.init(digitalSignature: true, keyCertSign: true, cRLSign: true)
)
XCTAssertEqual(cert.signatureAlgorithm, .ecdsaWithSHA384)
}
func testMatchingExtensionsViaExtensionBuilder() throws {
let binary = Array(Data(base64Encoded: Self.base64EncodedSampleCert, options: .ignoreUnknownCharacters)!)
let cert = try Certificate(derEncoded: binary)
let expectedExtensions = try Certificate.Extensions {
SubjectKeyIdentifier(keyIdentifier: [
0xE0, 0x85, 0x48, 0x7D, 0x13, 0xA6, 0xD3, 0x10, 0x19, 0x9F, 0x5C, 0xCB, 0x6B, 0x78, 0x24, 0x92, 0xF8,
0xAE, 0x1B, 0xAE,
])
AuthorityKeyIdentifier(keyIdentifier: [
0xB3, 0xDB, 0x48, 0xA4, 0xF9, 0xA1, 0xC5, 0xD8, 0xAE, 0x36, 0x41, 0xCC, 0x11, 0x63, 0x69, 0x62, 0x29,
0xBC, 0x4B, 0xC6,
])
Critical(
KeyUsage(digitalSignature: true, keyCertSign: true, cRLSign: true)
)
try ExtendedKeyUsage([.serverAuth, .clientAuth])
Critical(
BasicConstraints.isCertificateAuthority(maxPathLength: 0)
)
AuthorityInformationAccess([
.init(method: .ocspServer, location: .uniformResourceIdentifier("http://ocsp.digicert.com"))
])
// CRL Distribution Points
Certificate.Extension(
oid: [2, 5, 29, 31],
critical: false,
value: [
0x30, 0x39, 0x30, 0x37, 0xA0, 0x35, 0xA0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F,
0x2F, 0x63, 0x72, 0x6C, 0x33, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63,
0x6F, 0x6D, 0x2F, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x47, 0x6C, 0x6F, 0x62, 0x61,
0x6C, 0x52, 0x6F, 0x6F, 0x74, 0x47, 0x33, 0x2E, 0x63, 0x72, 0x6C,
]
)
// Certificate policies
Certificate.Extension(
oid: [2, 5, 29, 32],
critical: false,
value: [
0x30, 0x81, 0xD1, 0x30, 0x81, 0xC5, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xFD, 0x6C, 0x02,
0x01, 0x30, 0x81, 0xB7, 0x30, 0x28, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01,
0x16, 0x1C, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x64, 0x69,
0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x43, 0x50, 0x53, 0x30, 0x81,
0x8A, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x7E, 0x0C, 0x7C, 0x41,
0x6E, 0x79, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x43,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74,
0x69, 0x74, 0x75, 0x74, 0x65, 0x73, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6E, 0x63,
0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x65, 0x6C, 0x79, 0x69, 0x6E, 0x67,
0x20, 0x50, 0x61, 0x72, 0x74, 0x79, 0x20, 0x41, 0x67, 0x72, 0x65, 0x65, 0x6D, 0x65, 0x6E, 0x74,
0x20, 0x6C, 0x6F, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68, 0x74, 0x74, 0x70,
0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74,
0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x72, 0x70, 0x61, 0x2D, 0x75, 0x61, 0x30, 0x07, 0x06, 0x05, 0x67,
0x81, 0x0C, 0x01, 0x01,
]
)
}
XCTAssertEqual(cert.extensions, expectedExtensions)
}
func testSubjectKeyIdentifierHash() throws {
let binary = Array(Data(base64Encoded: Self.base64EncodedSampleCert, options: .ignoreUnknownCharacters)!)
let cert = try Certificate(derEncoded: binary)
XCTAssertEqual(try cert.extensions.subjectKeyIdentifier, SubjectKeyIdentifier(hash: cert.publicKey))
}
func testRSARootCert() throws {
let binary = Array(Data(base64Encoded: Self.base64EncodedRSARootCert, options: .ignoreUnknownCharacters)!)
let cert = try Certificate(derEncoded: binary)
XCTAssertTrue(cert.publicKey.isValidSignature(cert.signature, for: cert))
}
func testCodesignChain() throws {
let binaryCerts = Self.codesignCerts.map { Array(Data(base64Encoded: $0, options: .ignoreUnknownCharacters)!) }
let certs = try binaryCerts.map { try Certificate(derEncoded: $0) }
// Confirm basic signature validation.
XCTAssertTrue(certs[1].publicKey.isValidSignature(certs[0].signature, for: certs[0]))
XCTAssertTrue(certs[2].publicKey.isValidSignature(certs[1].signature, for: certs[1]))
}
func testReencodingDoesntChangeTheBytes() throws {
// This test validates that we don't change the TBS bytes when we re-encode a certificate.
//
// The easiest way to do this is to produce a slightly _weird_ certificate that encodes the signature algorithm
// in a way we wouldn't.
let name = try DistinguishedName {
CommonName("Test")
}
let key = try _RSA.Signing.PrivateKey(keySize: .bits2048)
var coder = DER.Serializer()
try coder.appendConstructedNode(identifier: .sequence) { coder in
try coder.serialize(
Certificate.Version.v3.rawValue,
explicitlyTaggedWithTagNumber: 0,
tagClass: .contextSpecific
)
try coder.serialize(Certificate.SerialNumber().bytes)
try coder.serialize(AlgorithmIdentifier.sha256WithRSAEncryptionUsingNil)
try coder.serialize(name)
try coder.serialize(
try Validity(notBefore: .makeTime(from: Date()), notAfter: .makeTime(from: Date() + 100))
)
try coder.serialize(name)
try coder.serialize(SubjectPublicKeyInfo(.init(key.publicKey)))
}
let tbsCertificateBytes = coder.serializedBytes
// Ok, we can construct this into a real certificate now by signing it and producing the signature block.
let signature = try Certificate.PrivateKey(key).sign(
bytes: tbsCertificateBytes,
signatureAlgorithm: .sha256WithRSAEncryption
)
coder = DER.Serializer()
try coder.appendConstructedNode(identifier: .sequence) { coder in
coder.serializeRawBytes(tbsCertificateBytes)
try coder.serialize(AlgorithmIdentifier.sha256WithRSAEncryptionUsingNil)
try coder.serialize(ASN1BitString(signature))
}
let serializedCert = coder.serializedBytes
// Great, done! Now we can deserialize this into a certificate, which should happen without error.
// Do a few spot checks to confirm it came out ok.
let cert = try Certificate(derEncoded: serializedCert)
XCTAssertEqual(cert.subject, name)
XCTAssertEqual(cert.issuer, name)
XCTAssertEqual(cert.version, .v3)
XCTAssertEqual(cert.signatureAlgorithm, .sha256WithRSAEncryption)
XCTAssertEqual(cert.publicKey, Certificate.PublicKey(key.publicKey))
XCTAssertTrue(Certificate.PublicKey(key.publicKey).isValidSignature(cert.signature, for: cert))
// Ok, serialize it back. We must not have canonicalised this.
coder = DER.Serializer()
try coder.serialize(cert)
let reserializedCert = coder.serializedBytes
XCTAssertEqual(reserializedCert, serializedCert)
}
func testRSAKeyFormatOutputIsCorrect() throws {
// A quick test here, we just encode and decode an RSA key.
let publicKey = try Certificate.PublicKey(_RSA.Signing.PrivateKey(keySize: .bits2048).publicKey)
let spki = SubjectPublicKeyInfo(publicKey)
var encoder = DER.Serializer()
try encoder.serialize(spki)
let decodedSPKI = try SubjectPublicKeyInfo(derEncoded: encoder.serializedBytes)
let newKey = try Certificate.PublicKey(spki: decodedSPKI)
XCTAssertEqual(publicKey, newKey)
}
func testIncorrectParameterSize() throws {
// This certificate tripped us up and revealed a bug in our ECDSA
// parsing, so let's use it as a regression test.
let cert = Array(
Data(
base64Encoded: """
MIIGATCCBYegAwIBAgIRAJt9HrGyczJOAAAAAFaglHwwCgYIKoZIzj0EAwIwgbox
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9T
ZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAx
NiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLjAsBgNV
BAMTJUVudHJ1c3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBMMUowHhcNMTkx
MTEzMDc0MTIwWhcNMjIwMjExMDgxMTE4WjCBpTELMAkGA1UEBhMCU0cxEjAQBgNV
BAcTCVNpbmdhcG9yZTETMBEGCysGAQQBgjc8AgEDEwJTRzEcMBoGA1UEChMTVGVt
YXNlayBQb2x5dGVjaG5pYzEaMBgGA1UEDxMRR292ZXJubWVudCBFbnRpdHkxEzAR
BgNVBAUTClQwOEdCMDA2MkwxHjAcBgNVBAMTFWlzaXMzb3NzY2V0LnRwLmVkdS5z
ZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABM2mA20fTxL81TOzHToOMpROOoUO
FVwGtdjQlCsN5TQ05Oazts57Cam4TRV437nibW2pHbv4Z6gX5cOj5vtGJFijggN/
MIIDezAgBgNVHREEGTAXghVpc2lzM29zc2NldC50cC5lZHUuc2cwggH1BgorBgEE
AdZ5AgQCBIIB5QSCAeEB3wB1AId1v+dZfPiMQ5lfvfNu/1aNR1Y2/0q1YMG06v9e
oIMPAAABbmPRJr0AAAQDAEYwRAIgDQlMMVr0sZ/vQ6TJayUKr/0uli6JsMdXra7+
AXtTAuACIHCqklPVac2HyjMHIcmB9Z9Ff/qdm80cTnJv2D2DF4f1AHYAVYHUwhaQ
NgFK6gubVzxT8MDkOHhwJQgXL6OqHQcT0wwAAAFuY9Em+QAABAMARzBFAiBlwOv7
uk+wVGWXmZur2HNFHUpY3EL72A6qp0+i+UlNKgIhAPUM6StlYsDeHFBcbwk8Mhsy
qvJ/cONzlQoi7aXSKen4AHYAVhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ
0N0AAAFuY9Em+wAABAMARzBFAiAYjMoE9baPZ9jtoL5cLi2hEQFcHmp2V/UkF5gS
MCkHbwIhAN0mbQvKboODaXXfPf3K9F5mRks2NYdrpV7I+uTsxxcwAHYAu9nfvB+K
cbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e0YUAAAFuY9EmtwAABAMARzBFAiEAocip
srDjKmlOd8Zo+mhFFVRmZYlgZMoLV/IvrMTEAFMCIFfzmKsxybQnMGX6iPbTU7nk
kAtsnNa6QaTEpRMVmsSEMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEF
BQcDAQYIKwYBBQUHAwIwYwYIKwYBBQUHAQEEVzBVMCMGCCsGAQUFBzABhhdodHRw
Oi8vb2NzcC5lbnRydXN0Lm5ldDAuBggrBgEFBQcwAoYiaHR0cDovL2FpYS5lbnRy
dXN0Lm5ldC9sMWotZWMxLmNlcjAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js
LmVudHJ1c3QubmV0L2xldmVsMWouY3JsMEoGA1UdIARDMEEwNgYKYIZIAYb6bAoB
AjAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L3JwYTAHBgVn
gQwBATAfBgNVHSMEGDAWgBTD+UUDvsj5CzxFNfPrcuzn6OuUmzAdBgNVHQ4EFgQU
7vNz5mM0I6JgWqm+556364tWmW8wCQYDVR0TBAIwADAKBggqhkjOPQQDAgNoADBl
AjBwybhS35Z4KFf1pt20LC9/CyxsDya3W/NbMn+bZ0RNNnOPABMv/Z3Xj7w086v4
PFcCMQDJVzG8VALwsAvO3JmKPy2LguNq0+pylaihUYGEg6rxxg5WyCXfnpZu0c+i
N5YHEvI=
""",
options: .ignoreUnknownCharacters
)!
)
XCTAssertNoThrow(try Certificate(derEncoded: cert))
}
func testUsingWeirdHashFunctions() async throws {
let now = Date()
let issuerKey = P384.Signing.PrivateKey()
let issuerName = try DistinguishedName {
CommonName("Issuer")
}
let issuer = try Certificate(
version: .v3,
serialNumber: .init(),
publicKey: .init(issuerKey.publicKey),
notValidBefore: now,
notValidAfter: now + 100,
issuer: issuerName,
subject: issuerName,
signatureAlgorithm: .ecdsaWithSHA384,
extensions: try Certificate.Extensions {
Critical(
BasicConstraints.isCertificateAuthority(maxPathLength: nil)
)
},
issuerPrivateKey: .init(issuerKey)
)
let leafKey = P384.Signing.PrivateKey()
let leafName = try DistinguishedName {
CommonName("Leaf")
}
let leaf = try Certificate(
version: .v3,
serialNumber: .init(),
publicKey: .init(leafKey.publicKey),
notValidBefore: now,
notValidAfter: now + 50,
issuer: issuerName,
subject: leafName,
signatureAlgorithm: .ecdsaWithSHA256,
extensions: try Certificate.Extensions {
Critical(
BasicConstraints.notCertificateAuthority
)
},
issuerPrivateKey: .init(issuerKey)
)
// We should be able to serialize and deserialize this, and have it remain equal.
var serializer = DER.Serializer()
try serializer.serialize(leaf)
let parsed = try Certificate(derEncoded: serializer.serializedBytes)
XCTAssertEqual(parsed, leaf)
// And we should be able to validate it.
let roots = CertificateStore([issuer])
var verifier = Verifier(rootCertificates: roots) {
RFC5280Policy(validationTime: now + 1)
}
let result = await verifier.validate(leafCertificate: parsed, intermediates: CertificateStore())
guard case .validCertificate(let chain) = result else {
XCTFail("Failed to validate cert")
return
}
XCTAssertEqual(chain, [parsed, issuer])
}
func testParsingBigNameConstraints() throws {
let cert = Array(
Data(
base64Encoded: """
MIIkKjCCIxKgAwIBAgIJIrmxaudci1hlMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw
JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMjAwMzIz
MDcxNzM2WhcNMjkwNTI5MDUwMDM5WjBbMQswCQYDVQQGEwJKUDEqMCgGA1UEChMh
TmF0aW9uYWwgSW5zdGl0dXRlIG9mIEluZm9ybWF0aWNzMSAwHgYDVQQDExdOSUkg
T3BlbiBEb21haW4gQ0EgLSBHNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAMvHidrFR7CRsutS5ioQCQBe5mtBfm1o7d5Hu111so+QrOMzZqtXMFTppYAG
qTWst4HW6nNIKgoFcbngQ2motJ44P57oTXu4kUHJO9qti/l9VVU+IIwPgb/xJk6R
jp5OcJfg5OPmDc6f3qmzl9803mKO1OO3ldDBGqq430cb1e6EfAD4xw+Rpr7fq5g3
PwW1v6cylM6ivOYxYwKhioPUFigzomVNSnCZMzZcsvIjsm+q0UkiCdJf9UcK8/uV
tW/3RWLO4SmqAxe+IMnjMO54Bpx1vyLm3jzDC3s4ndtAadQ7+GIvan9RsalRIhjM
e851BiXf1URA6BJAVW6bDVOS9ycCAwEAAaOCIO0wgiDpMB0GA1UdDgQWBBRnOjrB
a7ccpkFGOTCEyGkAWRFYwTAfBgNVHSMEGDAWgBQKhal3ZQWYfECB+A+XLDjxCuw8
zzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAU
BggrBgEFBQcDAQYIKwYBBQUHAwIwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL3Jl
cG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvU0NSb290MkNSTC5jcmww
UgYDVR0gBEswSTBHBgoqgwiMmxtkhwUEMDkwNwYIKwYBBQUHAgEWK2h0dHBzOi8v
cmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi8wgYUGCCsGAQUFBwEB
BHkwdzAwBggrBgEFBQcwAYYkaHR0cDovL3Njcm9vdGNhMi5vY3NwLnNlY29tdHJ1
c3QubmV0MEMGCCsGAQUFBzAChjdodHRwOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0
Lm5ldC9TQy1Sb290Mi9TQ1Jvb3QyY2EuY2VyMIIfOwYDVR0eBIIfMjCCHy6ggh74
MAuCCWFndS5hYy5qcDARgg9haWNoaS1lZHUuYWMuanAwE4IRYWljaGktZmFtLXUu
YWMuanAwE4IRYWljaGktbWVkLXUuYWMuanAwEIIOYWljaGktcHUuYWMuanAwEoIQ
YWljaGktdG9oby5hYy5qcDAPgg1haWNoaS11LmFjLmpwMA6CDGFpdGVjaC5hYy5q
cDAOggxha2FzaGkuYWMuanAwEYIPYWtpdGEtbmN0LmFjLmpwMA+CDWFraXRhLXUu
YWMuanAwEIIOYW5hbi1uY3QuYWMuanAwDoIMYW5kcmV3LmFjLmpwMAuCCWFwdS5h
Yy5qcDASghBhcmlha2UtbmN0LmFjLmpwMBWCE2FzYWhpa2F3YS1tZWQuYWMuanAw
FYITYXNhaGlrYXdhLW5jdC5hYy5qcDAPgg1hc2FoaS11LmFjLmpwMBCCDmJ1a2t5
by11LmFjLmpwMA6CDGJ1bmt5by5hYy5qcDAPgg1idW5yaS11LmFjLmpwMBCCDmNo
aWJha291ZGFpLmpwMA6CDGNoaWt5dS5hYy5qcDANggtjaHVidS5hYy5qcDAQgg5j
aHVreW8tdS5hYy5qcDAOggxjaHVvLXUuYWMuanAwEoIQY29uc29ydGl1bS5vci5q
cDAQgg5kYWlkby1pdC5hYy5qcDANggtkYWl0by5hYy5qcDAOggxkZW5kYWkuYWMu
anAwF4IVZGV2ZWxvcG1lbnQtc2Nob29sLmpwMA2CC2RvaHRvLmFjLmpwMBGCD2Rv
a2t5b21lZC5hYy5qcDAQgg5kb3NoaXNoYS5hYy5qcDAMggplZHVyb2FtLmpwMA+C
DWVoaW1lLXUuYWMuanAwDIIKZW5yaS5nby5qcDALgglmY3UuYWMuanAwDoIMZmRj
bmV0LmFjLmpwMA6CDGZlcnJpcy5hYy5qcDALgglmZXJyaXMuanAwC4IJZml0LmFj
LmpwMAuCCWZtdS5hYy5qcDALgglmcHUuYWMuanAwEYIPZnVqaXRhLWh1LmFjLmpw
MBGCD2Z1a3VpLW5jdC5hYy5qcDAOggxmdWt1am8uYWMuanAwE4IRZnVrdW9rYS1l
ZHUuYWMuanAwFYITZnVrdW9rYS1pbnQtdS5hYy5qcDARgg9mdWt1b2thLXUuYWMu
anAwFYITZnVrdXNoaW1hLW5jdC5hYy5qcDATghFmdWt1c2hpbWEtdS5hYy5qcDAS
ghBmdWt1eWFtYS11LmFjLmpwMAuCCWZ1bi5hYy5qcDAMggpnYWt1bmluLmpwMA+C
DWdpZnUtY24uYWMuanAwE4IRZ2lmdS1rZWl6YWkuYWMuanAwEIIOZ2lmdS1uY3Qu
YWMuanAwD4INZ2lmdS1wdS5hYy5qcDAOggxnaWZ1LXUuYWMuanAwC4IJZ2t1LmFj
LmpwMA2CC2dyaXBzLmFjLmpwMBCCDmd1bm1hLWN0LmFjLmpwMA+CDWd1bm1hLXUu
YWMuanAwFIISaGFjaGlub2hlLWN0LmFjLmpwMBOCEWhhY2hpbm9oZS11LmFjLmpw
MBOCEWhha29kYXRlLWN0LmFjLmpwMBCCDmhhbWEtbWVkLmFjLmpwMBSCEmhlaXNl
aS1pcnlvdS5hYy5qcDAQgg5oZWlzZWktdS5hYy5qcDAIggZoZ3UuanAwDIIKaGly
b2RhaS5qcDAPgg1oaXJva291ZGFpLmpwMBKCEGhpcm9zYWtpLXUuYWMuanAwFYIT
aGlyb3NoaW1hLWNtdC5hYy5qcDAUghJoaXJvc2hpbWEtY3UuYWMuanAwE4IRaGly
b3NoaW1hLXUuYWMuanAwEIIOaGlyb3NoaW1hLXUuanAwD4INaGktdGVjaC5hYy5q
cDANggtoaXQtdS5hYy5qcDAMggpobWpjLmFjLmpwMBKCEGhva2thaS1zLXUuYWMu
anAwEYIPaG9ra3lvZGFpLmFjLmpwMA+CDWhva3VkYWkuYWMuanAwE4IRaG9rdS1p
cnlvLXUuYWMuanAwEoIQaG9rdXJpa3UtdS5hYy5qcDAPgg1oeW9nby11LmFjLmpw
MA2CC2lhbWFzLmFjLmpwMAqCCGlhbWFzLmpwMA+CDWliYXJha2kuYWMuanAwEoIQ
aWJhcmFraS1jdC5hYy5qcDALgglpY2MuYWMuanAwEoIQaWNoaW5vc2VraS5hYy5q
cDALgglpY3UuYWMuanAwEIIOaWdha3VrZW4ub3IuanAwC4IJaW1zLmFjLmpwMBCC
DmludGVybmV0LmFjLmpwMAuCCWlvdC5hYy5qcDAJggdpcG11LmpwMA6CDGlyaS10
b2t5by5qcDAKgghpcm9vcC5qcDAUghJpc2hpa2F3YS1uY3QuYWMuanAwC4IJaXNt
LmFjLmpwMBCCDml0LWNoaWJhLmFjLmpwMBSCEml0LWhpcm9zaGltYS5hYy5qcDAP
gg1pd2FraW11LmFjLmpwMBGCD2l3YXRlLW1lZC5hYy5qcDAPgg1pd2F0ZS11LmFj
LmpwMA2CC2phaXN0LmFjLmpwMA+CDWphbXN0ZWMuZ28uanAwCYIHamF4YS5qcDAM
ggpqLWZvY3VzLmpwMA2CC2ppY2hpLmFjLmpwMA6CDGppbi1haS5hYy5qcDAOggxq
aW5kYWkuYWMuanAwDYILam9zaG8uYWMuanAwC4IJai1wYXJjLmpwMA6CDGpyY2hj
bi5hYy5qcDAMggpqc3BzLmdvLmpwMAyCCmp1ZW4uYWMuanAwFYITa2FjaG8tY29s
bGVnZS5hYy5qcDAOggxrYWV0c3UuYWMuanAwEoIQa2FnYXdhLW5jdC5hYy5qcDAQ
gg5rYWdhd2EtdS5hYy5qcDAUghJrYWdvc2hpbWEtY3QuYWMuanAwE4IRa2Fnb3No
aW1hLXUuYWMuanAwEIIOa2FpeW9kYWkuYWMuanAwE4IRa2FuYWdhd2EtaXQuYWMu
anAwE4IRa2FuYXphd2EtZ3UuYWMuanAwEoIQa2FuYXphd2EtdS5hYy5qcDALgglr
YW5kYWkuanAwEIIOa2Fuc2FpLXUuYWMuanAwFIISa2FzZWktZ2FrdWluLmFjLmpw
MAuCCWtidS5hYy5qcDALgglrY3QuYWMuanAwDIIKa2N1YS5hYy5qcDAMggprZWlv
LmFjLmpwMAmCB2tlaW8uanAwCIIGa2VrLmpwMA6CDGtpbmRhaS5hYy5qcDARgg9r
aW5qby1nYWt1aW4uanAwD4INa2luam8tdS5hYy5qcDAPgg1raXJ5dS11LmFjLmpw
MBCCDmtpc2FyYXp1LmFjLmpwMAuCCWtpdC5hYy5qcDAIggZraXQuanAwEYIPa2l0
YWt5dS11LmFjLmpwMBGCD2tpdGFtaS1pdC5hYy5qcDARgg9rLWp1bnNoaW4uYWMu
anAwDoIMa29iZS1jLmFjLmpwMBGCD2tvYmUtY29sbGVnZS5qcDARgg9rb2JlLWN1
ZnMuYWMuanAwEoIQa29iZS1rb3Nlbi5hYy5qcDATghFrb2JlLXRva2l3YS5hYy5q
cDAOggxrb2JlLXUuYWMuanAwEIIOa29jaGktY3QuYWMuanAwDYILa29jaGktY3Qu
anAwEIIOa29jaGktbXMuYWMuanAwEoIQa29jaGktdGVjaC5hYy5qcDAPgg1rb2No
aS11LmFjLmpwMAyCCmtvY2hpLXUuanAwEIIOa29nYWt1aW4uYWMuanAwEoIQa29r
dWdha3Vpbi5hYy5qcDASghBrb2t1c2hpa2FuLmFjLmpwMA2CC2tvc2VuLWFjLmpw
MA+CDWtvc2VuLWsuZ28uanAwDYILa3BwdWMuYWMuanAwC4IJa3B1LmFjLmpwMA2C
C2twdS1tLmFjLmpwMAyCCmt1YXMuYWMuanAwDIIKa3Vmcy5hYy5qcDALgglrdWlu
cy5uZXQwEIIOa3VtYWdha3UuYWMuanAwFIISa3VtYW1vdG8taHN1LmFjLmpwMBSC
Emt1bWFtb3RvLW5jdC5hYy5qcDASghBrdW1hbW90by11LmFjLmpwMBGCD2t1bml0
YWNoaS5hYy5qcDAQgg5rdXJlLW5jdC5hYy5qcDARgg9rdXJ1bWUtaXQuYWMuanAw
EoIQa3VydW1lLW5jdC5hYy5qcDAVghNrdXJ1bWUtc2hpbmFpLmFjLmpwMBCCDmt1
cnVtZS11LmFjLmpwMBKCEGt1c2hpcm8tY3QuYWMuanAwDIIKa3d1Yy5hYy5qcDAP
gg1reW9oYWt1LmdvLmpwMBCCDmt5b2t5by11LmFjLmpwMBGCD2t5b3RvLWFydC5h
Yy5qcDASghBreW90by1lY29uLmFjLmpwMBWCE2t5b3RvZ2FrdWVuLXUuYWMuanAw
FIISa3lvdG9rYWNoby11LmFjLmpwMBCCDmt5b3RvLXN1LmFjLmpwMA+CDWt5b3Rv
LXUuYWMuanAwDIIKa3lvdG8tdS5qcDAQgg5reW90by13dS5hYy5qcDAQgg5reXUt
ZGVudC5hYy5qcDAQgg5reXVreW8tdS5hYy5qcDAQgg5reXVzYW4tdS5hYy5qcDAQ
gg5reXVzaHUtdS5hYy5qcDAPgg1reXV0ZWNoLmFjLmpwMAyCCmt5dXRlY2guanAw
EoIQbWFpenVydS1jdC5hYy5qcDARgg9tYXRzdWUtY3QuYWMuanAwDoIMbWF0c3Vl
LWN0LmpwMBOCEW1hdHN1eWFtYS11LmFjLmpwMBCCDm1hdHN1eWFtYS11LmpwMA+C
DW1laWppLXUuYWMuanAwDoIMbWVpby11LmFjLmpwMBCCDm1laXJpbi1jLmFjLmpw
MA6CDG1lamlyby5hYy5qcDARgg9tZXRyby1jaXQuYWMuanAwDYILbWllLXUuYWMu
anAwD4INbWlucGFrdS5hYy5qcDAWghRtaXlha29ub2pvLW5jdC5hYy5qcDARgg9t
aXlha3lvLXUuYWMuanAwFIISbWl5YXNhbmtlaS11LmFjLmpwMBOCEW1peWF6YWtp
LW11LmFjLmpwMBKCEG1peWF6YWtpLXUuYWMuanAwC4IJbXB1LmFjLmpwMBKCEG11
cm9yYW4taXQuYWMuanAwDoIMbXVzYWJpLmFjLmpwMAuCCW15anVlbi5qcDAQgg5t
eS1waGFybS5hYy5qcDALgglteXUuYWMuanAwEIIObmFidW5rZW4uZ28uanAwDoIM
bmFnYW5vLmFjLmpwMBKCEG5hZ2Fuby1uY3QuYWMuanAwEoIQbmFnYW9rYS1jdC5h
Yy5qcDARgg9uYWdhb2thdXQuYWMuanAwEoIQbmFnYXNha2ktdS5hYy5qcDAUghJu
YWdveWEtYnVucmkuYWMuanAwEYIPbmFnb3lhLWN1LmFjLmpwMBCCDm5hZ295YS11
LmFjLmpwMA2CC25hZ295YS11LmpwMBGCD25hZ295YS13dS5hYy5qcDAKgghuYWlz
dC5qcDARgg9uYWthbmlzaGkuYWMuanAwC4IJbmFuemFuLmpwMBCCDm5hbnphbi11
LmFjLmpwMAuCCW5hby5hYy5qcDAQgg5uYXJhLWVkdS5hYy5qcDAQgg5uYXJhaGFr
dS5nby5qcDAOggxuYXJhLWsuYWMuanAwEYIPbmFyYW1lZC11LmFjLmpwMA+CDW5h
cmEtd3UuYWMuanAwDIIKbmFyZWdpLm9yZzAQgg5uYXJ1dG8tdS5hYy5qcDAMggpu
Y2dnLmdvLmpwMAyCCm5jZ20uZ28uanAwDIIKbmNucC5nby5qcDARgg9uYy10b3lh
bWEuYWMuanAwDoIMbmV0bmZ1Lm5lLmpwMA2CC25ldXJvaW5mLmpwMAiCBm5mdS5q
cDALggluZnUubmUuanAwEYIPbi1mdWt1c2hpLmFjLmpwMAyCCm5pYXMuYWMuanAw
DIIKbmliYi5hYy5qcDAMggpuaWNoLmdvLmpwMBCCDm5pY2hpYnVuLmFjLmpwMAyC
Cm5pZnMuYWMuanAwDoIMbmlmcy1rLmFjLmpwMAuCCW5pZy5hYy5qcDALggluaWgu
Z28uanAwD4INbmlob24tdS5hYy5qcDAJggduaWh1LmpwMAuCCW5paS5hYy5qcDAM
ggpuaWlkLmdvLmpwMBGCD25paWdhdGEtdS5hYy5qcDATghFuaWloYW1hLW5jdC5h
Yy5qcDAMggpuaW1zLmdvLmpwMA6CDG5pbmphbC5hYy5qcDAJggduaW5zLmpwMAyC
Cm5pcGguZ28uanAwDIIKbmlwci5hYy5qcDAMggpuaXBzLmFjLmpwMBaCFG5pc2hv
Z2FrdXNoYS11LmFjLmpwMA6CDG5pdGVjaC5hYy5qcDALggluaXRlY2guanAwDoIM
bml0dGFpLmFjLmpwMAyCCm5peWUuZ28uanAwDYILbm9kYWkuYWMuanAwEIIObi1z
ZWlyeW8uYWMuanAwC4IJbnVhLmFjLmpwMAyCCm51YXMuYWMuanAwDYILbnVjYmEu
YWMuanAwDIIKbnVmcy5hYy5qcDAMggpudWh3LmFjLmpwMAyCCm51aXMuYWMuanAw
EYIPbnVtYXp1LWN0LmFjLmpwMAmCB253ZWMuanAwD4INb2JpaGlyby5hYy5qcDAO
ggxvYmlyaW4uYWMuanAwDIIKb2NoYS5hYy5qcDAJggdvaXN0LmpwMAuCCW9pdC5h
Yy5qcDAPgg1vaXRhLWN0LmFjLmpwMA6CDG9pdGEtdS5hYy5qcDALgglva2FkYWku
anAwDoIMb2thLXB1LmFjLmpwMBGCD29rYXlhbWEtdS5hYy5qcDASghBva2luYXdh
LWN0LmFjLmpwMBGCD29raW5hd2EtdS5hYy5qcDAMggpva2l1LmFjLmpwMBKCEG9u
b21pY2hpLXUuYWMuanAwDIIKb3Blbi5lZC5qcDAOggxvc2FrYWMuYWMuanAwEIIO
b3Nha2EtY3UuYWMuanAwEYIPb3Nha2FmdS11LmFjLmpwMBSCEm9zYWthLWt5b2lr
dS5hYy5qcDARgg9vc2FrYS1wY3QuYWMuanAwD4INb3Nha2EtdS5hYy5qcDAQgg5v
c2hpbWEtay5hYy5qcDANggtvdGFuaS5hYy5qcDAQgg5vdGFydS11Yy5hYy5qcDAO
ggxvdGVtb24uYWMuanAwDIIKb3Vocy5hYy5qcDALgglvdXMuYWMuanAwEIIOb3lh
bWEtY3QuYWMuanAwCoIIcGRiai5vcmcwFIIScHUtaGlyb3NoaW1hLmFjLmpwMBOC
EXB1LWt1bWFtb3RvLmFjLmpwMAuCCXFzdC5nby5qcDAOggxyYWt1bm8uYWMuanAw
DYILcmVoYWIuZ28uanAwEYIPcmVpdGFrdS11LmFjLmpwMBCCDnJla2loYWt1LmFj
LmpwMA2CC3Jpa2VuLmdvLmpwMAqCCHJpa2VuLmpwMA6CDHJpa2t5by5hYy5qcDAO
ggxyaWtreW8ubmUuanAwEIIOcml0c3VtZWkuYWMuanAwC4IJcmt1LmFjLmpwMAyC
CnJvaXMuYWMuanAwEYIPcnVjb25zb3J0aXVtLmpwMA+CDXJ5dWtva3UuYWMuanAw
DoIMc2FnYS11LmFjLmpwMBGCD3NhaXRhbWEtdS5hYy5qcDANggtzYW5uby5hYy5q
cDAOggxzYXBtZWQuYWMuanAwEYIPc2FwcG9yby11LmFjLmpwMA6CDHNhc2Viby5h
Yy5qcDALgglzY3UuYWMuanAwDYILc2Vpam8uYWMuanAwEIIOc2Vpam9oLXUuYWMu
anAwDoIMc2Vpa2VpLmFjLmpwMBKCEHNlaW5hbi1nYWt1aW4uanAwEYIPc2VpbmFu
LWd1LmFjLmpwMA6CDHNlaXJlaS5hYy5qcDASghBzZWlzYWRvaHRvLmFjLmpwMA6C
DHNlaXNlbi5hYy5qcDAQgg5zZWlzZW4tdS5hYy5qcDASghBzZW5kYWktbmN0LmFj
LmpwMBCCDnNlbnNodS11LmFjLmpwMA2CC3NlbnNodS11LmpwMBCCDnNldHN1bmFu
LmFjLmpwMAuCCXNnay5hYy5qcDALgglzZ3UuYWMuanAwE4IRc2hpYmF1cmEtaXQu
YWMuanAwDoIMc2hpZ2Fra2FuLmpwMBGCD3NoaWdhLW1lZC5hYy5qcDAPgg1zaGln
YS11LmFjLmpwMBGCD3NoaW1hbmUtdS5hYy5qcDAWghRzaGltb25vc2VraS1jdS5h
Yy5qcDARgg9zaGlub25vbWUuYWMuanAwEYIPc2hpbnNodS11LmFjLmpwMBGCD3No
aXJheXVyaS5hYy5qcDAQgg5zaGl6dW9rYS5hYy5qcDAOggxzaG9kYWkuYWMuanAw
DoIMc2hva2VpLmFjLmpwMBGCD3Nob25hbi1pdC5hYy5qcDAPgg1zaG90b2t1LmFj
LmpwMAyCCnNob3Rva3UuanAwD4INc2hvd2EtdS5hYy5qcDAOggxzaHVidW4uYWMu
anAwDYILc2luZXQuYWQuanAwDIIKc2lzdC5hYy5qcDALgglzaXUuYWMuanAwDIIK
c29jdS5hYy5qcDAOggxzb2pvLXUuYWMuanAwDIIKc29rYS5hYy5qcDANggtzb2tl
bi5hYy5qcDAPgg1zcHJpbmc4Lm9yLmpwMBKCEHN1Z2l5YW1hLXUuYWMuanAwEYIP
c3V6dWthLWN0LmFjLmpwMAuCCXN3dS5hYy5qcDAQgg50YW1hZ2F3YS5hYy5qcDAN
ggt0YW1hZ2F3YS5qcDALggl0YXUuYWMuanAwC4IJdGN1LmFjLmpwMAyCCnRjdWUu
YWMuanAwC4IJdGRjLmFjLmpwMBCCDnRlaWt5by11LmFjLmpwMA6CDHRlbnNoaS5h
Yy5qcDAUghJ0ZXp1a2F5YW1hLXUuYWMuanAwCIIGdGd1LmpwMAuCCXRodS5hYy5q
cDAOggx0aXRlY2guYWMuanAwC4IJdG1kLmFjLmpwMAiCBnRubS5qcDAQgg50b2Jh
LWNtdC5hYy5qcDAQgg50b2J1bmtlbi5nby5qcDAOggx0b2hva3UuYWMuanAwFYIT
dG9ob2t1LWdha3Vpbi5hYy5qcDASghB0b2hva3UtZ2FrdWluLmpwMBKCEHRvaG9r
dS1tcHUuYWMuanAwDoIMdG9oby11LmFjLmpwMA+CDXRvaHRlY2guYWMuanAwDoIM
dG9raXdhLmFjLmpwMA6CDHRva29oYS5hYy5qcDARgg90b2tvaGEtamMuYWMuanAw
EIIOdG9rb2hhLXUuYWMuanAwE4IRdG9rdXNoaW1hLXUuYWMuanAwEIIOdG9rdXlh
bWEuYWMuanAwEIIOdG9reW8tY3QuYWMuanAwFIISdG9tYWtvbWFpLWN0LmFjLmpw
MBGCD3RvdHRvcmktdS5hYy5qcDAOggx0b3lha3UuYWMuanAwDIIKdG95by5hYy5q
cDARgg90b3lvdGEtY3QuYWMuanAwD4INdHN1a3ViYS5hYy5qcDARgg90c3VrdWJh
LWcuYWMuanAwFIISdHN1a3ViYS10ZWNoLmFjLmpwMBSCEnRzdXJ1LWdha3Vlbi5h
Yy5qcDARgg90c3VydW1pLXUuYWMuanAwFIISdHN1cnVva2EtbmN0LmFjLmpwMBKC
EHRzdXlhbWEtY3QuYWMuanAwDIIKdHVhdC5hYy5qcDAMggp0dWZzLmFjLmpwMAyC
CnR1aXMuYWMuanAwDIIKdHVzeS5hYy5qcDALggl0dXQuYWMuanAwDIIKdHdjdS5h
Yy5qcDAOggx1LWFpenUuYWMuanAwDYILdWJlLWsuYWMuanAwC4IJdWVjLmFjLmpw
MA+CDXUtZnVrdWkuYWMuanAwEYIPdS1nYWt1Z2VpLmFjLmpwMA+CDXUtaHlvZ28u
YWMuanAwD4INdS1rb2NoaS5hYy5qcDAQgg51LW5hZ2Fuby5hYy5qcDAPgg11bml2
ZXJzaXR5LmpwMA6CDHVvZWgtdS5hYy5qcDAJggd1cGtpLmpwMBCCDnUtcnl1a3l1
LmFjLmpwMBGCD3Utc2hpbWFuZS5hYy5qcDAWghR1LXNoaXp1b2thLWtlbi5hYy5q
cDAPgg11LXRva3lvLmFjLmpwMBCCDnUtdG95YW1hLmFjLmpwMBSCEnV0c3Vub21p
eWEtdS5hYy5qcDAUghJ3YWtheWFtYS1uY3QuYWMuanAwEoIQd2FrYXlhbWEtdS5h
Yy5qcDAOggx3YWtob2suYWMuanAwEoIQeWFtYWdhdGEtdS5hYy5qcDATghF5YW1h
Z3VjaGktdS5hYy5qcDARgg95YW1hbmFzaGkuYWMuanAwDIIKeWdqYy5hYy5qcDAL
ggl5Z3UuYWMuanAwC4IJeW51LmFjLmpwMBCCDnlvbmFnby1rLmFjLmpwMAyCCnl1
Z2UuYWMuanAwEYIPdGVpa3lvLWpjLmFjLmpwMBCCDm9zYWthLXVlLmFjLmpwMA2C
C3RzdWRhLmFjLmpwMAuCCW5ndS5hYy5qcDALggljMmMuYWMuanAwDoIMYW95YW1h
LmFjLmpwMBGCD3VwYy1vc2FrYS5hYy5qcDAIggZmaXQuanAwE4IRZnVrdW9rYS13
amMuYWMuanChMDAKhwgAAAAAAAAAADAihyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADANBgkqhkiG9w0BAQsFAAOCAQEAxWH4we4kk599n+wSNrDE1GDB
1P+tBW+X0EUHMeow5Db6EzNFBVr/bgxD/4dTKh0coWo6wzExCBKwag9S4j2eYNre
uy8X++HPRoXEqoKhOAIvgj9RLw1eGhW6OJoC++pUXHOAINUrYLgpwxiAZfw0oDAe
+NrOXXP/LwDP85gKq+2/QGCsENsxLC4tLhonANethBLExpHaiUhjDVD3IO8w9cmE
Fm4c6j6onhml5MChBfLeNoXlc7lG+CKgIV4lQ1AuedV/FcYtNXqADOe5hO4IKENQ
PBsG3+c22LGvqt4DsBMYHiGU4AFzT5BLWrYZv1TMIUQ+lSOWvLIsTQSN6WgQ3w==
""",
options: .ignoreUnknownCharacters
)!
)
let decoded = try Certificate(derEncoded: cert)
XCTAssertNoThrow(try decoded.extensions.nameConstraints)
}
}
|