|
38 | 38 |
|
39 | 39 | #include <wolfssl/internal.h> |
40 | 40 | #include <wolfssl/wolfcrypt/asn.h> |
| 41 | +#include <wolfssl/wolfcrypt/asn_public.h> |
41 | 42 |
|
42 | 43 | #if defined(OPENSSL_ALL) && \ |
43 | 44 | defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) |
@@ -632,3 +633,245 @@ int test_x509_time_field_overread_via_tls(void) |
632 | 633 | #endif /* compile guards */ |
633 | 634 | return EXPECT_RESULT(); |
634 | 635 | } |
| 636 | + |
| 637 | + |
| 638 | +/* Test that CertFromX509 rejects an oversized raw AuthorityKeyIdentifier |
| 639 | + * extension. Before the fix, the guard checked authKeyIdSz (the [0] |
| 640 | + * keyIdentifier sub-field) but the WOLFSSL_AKID_NAME branch copied |
| 641 | + * authKeyIdSrcSz (the full extension) bytes, causing a heap overflow. */ |
| 642 | +int test_x509_CertFromX509_akid_overflow(void) |
| 643 | +{ |
| 644 | + EXPECT_DECLS; |
| 645 | +#if defined(WOLFSSL_AKID_NAME) && defined(WOLFSSL_CERT_GEN) && \ |
| 646 | + defined(WOLFSSL_CERT_EXT) && !defined(NO_BIO) && \ |
| 647 | + (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) |
| 648 | + /* DER builder helpers -- write into a flat buffer */ |
| 649 | +#ifdef WOLFSSL_SMALL_STACK |
| 650 | + unsigned char* buf = NULL; |
| 651 | +#else |
| 652 | + unsigned char buf[16384]; |
| 653 | +#endif |
| 654 | + size_t pos = 0; |
| 655 | + size_t akid_val_len; |
| 656 | + unsigned char* akid_val = NULL; |
| 657 | + WOLFSSL_X509* x = NULL; |
| 658 | + WOLFSSL_BIO* bio = NULL; |
| 659 | + |
| 660 | +#ifdef WOLFSSL_SMALL_STACK |
| 661 | + buf = (unsigned char*)XMALLOC(16384, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| 662 | + ExpectNotNull(buf); |
| 663 | + if (buf == NULL) |
| 664 | + return EXPECT_RESULT(); |
| 665 | +#endif |
| 666 | + |
| 667 | + #define PUT1(b) do { buf[pos++] = (b); } while(0) |
| 668 | + #define PUTN(p, n) do { XMEMCPY(buf + pos, (p), (n)); pos += (n); } while(0) |
| 669 | + |
| 670 | + /* Emit tag + definite-length header, return header size */ |
| 671 | + #define TLV_HDR(tag, n, out, hlen) do { \ |
| 672 | + size_t _i = 0; \ |
| 673 | + (out)[_i++] = (tag); \ |
| 674 | + if ((n) < 0x80u) { (out)[_i++] = (unsigned char)(n); } \ |
| 675 | + else if ((n) < 0x100u) { (out)[_i++] = 0x81; \ |
| 676 | + (out)[_i++] = (unsigned char)(n); } \ |
| 677 | + else if ((n) < 0x10000u) { (out)[_i++] = 0x82; \ |
| 678 | + (out)[_i++] = (unsigned char)((n)>>8); \ |
| 679 | + (out)[_i++] = (unsigned char)(n); } \ |
| 680 | + (hlen) = _i; \ |
| 681 | + } while(0) |
| 682 | + |
| 683 | + /* Wrap [start, pos) in-place with a TLV header */ |
| 684 | + #define WRAP(start, tag) do { \ |
| 685 | + size_t _len = pos - (start); \ |
| 686 | + unsigned char _hdr[6]; size_t _hlen; \ |
| 687 | + TLV_HDR((tag), _len, _hdr, _hlen); \ |
| 688 | + XMEMMOVE(buf + (start) + _hlen, buf + (start), _len); \ |
| 689 | + XMEMCPY(buf + (start), _hdr, _hlen); \ |
| 690 | + pos += _hlen; \ |
| 691 | + } while(0) |
| 692 | + |
| 693 | + /* ---- Build AKID extension value ---- */ |
| 694 | + { |
| 695 | + size_t akid_start = pos; |
| 696 | + size_t s; |
| 697 | + int i; |
| 698 | + |
| 699 | + /* [0] keyIdentifier: 20 bytes (small, passes old check) */ |
| 700 | + s = pos; |
| 701 | + for (i = 0; i < 20; i++) PUT1(0x41); |
| 702 | + WRAP(s, 0x80); |
| 703 | + |
| 704 | + /* [1] authorityCertIssuer: one URI of ~4000 bytes |
| 705 | + * This makes authKeyIdSrcSz >> sizeof(cert->akid) (~1628) */ |
| 706 | + s = pos; |
| 707 | + { |
| 708 | + const char* pfx = "http://e/"; |
| 709 | + PUTN(pfx, (size_t)XSTRLEN(pfx)); |
| 710 | + for (i = 0; i < 4000; i++) PUT1('Z'); |
| 711 | + } |
| 712 | + WRAP(s, 0x86); /* GeneralName [6] URI */ |
| 713 | + WRAP(s, 0xA1); /* [1] IMPLICIT */ |
| 714 | + |
| 715 | + /* [2] authorityCertSerialNumber */ |
| 716 | + s = pos; |
| 717 | + PUT1(0x01); |
| 718 | + WRAP(s, 0x82); |
| 719 | + |
| 720 | + WRAP(akid_start, 0x30); /* SEQUENCE */ |
| 721 | + akid_val_len = pos - akid_start; |
| 722 | + akid_val = (unsigned char*)XMALLOC(akid_val_len, NULL, |
| 723 | + DYNAMIC_TYPE_TMP_BUFFER); |
| 724 | + ExpectNotNull(akid_val); |
| 725 | + if (akid_val != NULL) |
| 726 | + XMEMCPY(akid_val, buf + akid_start, akid_val_len); |
| 727 | + } |
| 728 | + |
| 729 | + /* ---- Build minimal self-signed v3 certificate ---- */ |
| 730 | + pos = 0; |
| 731 | + { |
| 732 | + size_t tbs_start = pos; |
| 733 | + size_t s; |
| 734 | + |
| 735 | + /* version [0] EXPLICIT INTEGER 2 (v3) */ |
| 736 | + PUT1(0xA0); PUT1(0x03); PUT1(0x02); PUT1(0x01); PUT1(0x02); |
| 737 | + |
| 738 | + /* serialNumber INTEGER 1 */ |
| 739 | + PUT1(0x02); PUT1(0x01); PUT1(0x01); |
| 740 | + |
| 741 | + /* signature: ecdsa-with-SHA256 */ |
| 742 | + s = pos; |
| 743 | + { |
| 744 | + unsigned char oid[] = {0x06,0x08,0x2A,0x86,0x48,0xCE, |
| 745 | + 0x3D,0x04,0x03,0x02}; |
| 746 | + PUTN(oid, sizeof(oid)); |
| 747 | + } |
| 748 | + WRAP(s, 0x30); |
| 749 | + |
| 750 | + /* issuer: CN=A */ |
| 751 | + s = pos; |
| 752 | + { |
| 753 | + size_t rdn = pos, atv = pos; |
| 754 | + unsigned char cn[] = {0x06,0x03,0x55,0x04,0x03}; |
| 755 | + PUTN(cn, sizeof(cn)); |
| 756 | + PUT1(0x0C); PUT1(0x01); PUT1('A'); |
| 757 | + WRAP(atv, 0x30); WRAP(rdn, 0x31); WRAP(s, 0x30); |
| 758 | + } |
| 759 | + |
| 760 | + /* validity */ |
| 761 | + s = pos; |
| 762 | + { |
| 763 | + unsigned char t1[] = {0x17,0x0D,'2','5','0','1','0','1', |
| 764 | + '0','0','0','0','0','0','Z'}; |
| 765 | + unsigned char t2[] = {0x17,0x0D,'3','5','0','1','0','1', |
| 766 | + '0','0','0','0','0','0','Z'}; |
| 767 | + PUTN(t1, sizeof(t1)); PUTN(t2, sizeof(t2)); |
| 768 | + } |
| 769 | + WRAP(s, 0x30); |
| 770 | + |
| 771 | + /* subject: CN=A */ |
| 772 | + s = pos; |
| 773 | + { |
| 774 | + size_t rdn = pos, atv = pos; |
| 775 | + unsigned char cn[] = {0x06,0x03,0x55,0x04,0x03}; |
| 776 | + PUTN(cn, sizeof(cn)); |
| 777 | + PUT1(0x0C); PUT1(0x01); PUT1('A'); |
| 778 | + WRAP(atv, 0x30); WRAP(rdn, 0x31); WRAP(s, 0x30); |
| 779 | + } |
| 780 | + |
| 781 | + /* subjectPublicKeyInfo: EC P-256 with dummy point */ |
| 782 | + s = pos; |
| 783 | + { |
| 784 | + size_t alg = pos, bs; |
| 785 | + unsigned char ecpk[] = {0x06,0x07,0x2A,0x86,0x48,0xCE, |
| 786 | + 0x3D,0x02,0x01}; |
| 787 | + unsigned char p256[] = {0x06,0x08,0x2A,0x86,0x48,0xCE, |
| 788 | + 0x3D,0x03,0x01,0x07}; |
| 789 | + PUTN(ecpk, sizeof(ecpk)); |
| 790 | + PUTN(p256, sizeof(p256)); |
| 791 | + WRAP(alg, 0x30); |
| 792 | + bs = pos; |
| 793 | + PUT1(0x00); PUT1(0x04); |
| 794 | + /* Use P-256 generator point (valid on-curve point) so that |
| 795 | + * builds with WOLFSSL_VALIDATE_ECC_IMPORT accept the key. */ |
| 796 | + { |
| 797 | + static const unsigned char p256G[64] = { |
| 798 | + 0x6B,0x17,0xD1,0xF2,0xE1,0x2C,0x42,0x47, |
| 799 | + 0xF8,0xBC,0xE6,0xE5,0x63,0xA4,0x40,0xF2, |
| 800 | + 0x77,0x03,0x7D,0x81,0x2D,0xEB,0x33,0xA0, |
| 801 | + 0xF4,0xA1,0x39,0x45,0xD8,0x98,0xC2,0x96, |
| 802 | + 0x4F,0xE3,0x42,0xE2,0xFE,0x1A,0x7F,0x9B, |
| 803 | + 0x8E,0xE7,0xEB,0x4A,0x7C,0x0F,0x9E,0x16, |
| 804 | + 0x2B,0xCE,0x33,0x57,0x6B,0x31,0x5E,0xCE, |
| 805 | + 0xCB,0xB6,0x40,0x68,0x37,0xBF,0x51,0xF5 |
| 806 | + }; |
| 807 | + PUTN(p256G, sizeof(p256G)); |
| 808 | + } |
| 809 | + WRAP(bs, 0x03); |
| 810 | + } |
| 811 | + WRAP(s, 0x30); |
| 812 | + |
| 813 | + /* extensions [3] */ |
| 814 | + { |
| 815 | + size_t exts_outer = pos, exts_seq = pos, ext = pos, ev; |
| 816 | + unsigned char akid_oid[] = {0x06,0x03,0x55,0x1D,0x23}; |
| 817 | + PUTN(akid_oid, sizeof(akid_oid)); |
| 818 | + ev = pos; |
| 819 | + if (akid_val != NULL) |
| 820 | + PUTN(akid_val, akid_val_len); |
| 821 | + WRAP(ev, 0x04); |
| 822 | + WRAP(ext, 0x30); |
| 823 | + WRAP(exts_seq, 0x30); |
| 824 | + WRAP(exts_outer, 0xA3); |
| 825 | + } |
| 826 | + |
| 827 | + WRAP(tbs_start, 0x30); |
| 828 | + |
| 829 | + /* signatureAlgorithm */ |
| 830 | + s = pos; |
| 831 | + { |
| 832 | + unsigned char oid[] = {0x06,0x08,0x2A,0x86,0x48,0xCE, |
| 833 | + 0x3D,0x04,0x03,0x02}; |
| 834 | + PUTN(oid, sizeof(oid)); |
| 835 | + } |
| 836 | + WRAP(s, 0x30); |
| 837 | + |
| 838 | + /* signatureValue: dummy */ |
| 839 | + s = pos; |
| 840 | + { |
| 841 | + size_t sig; |
| 842 | + PUT1(0x00); |
| 843 | + sig = pos; |
| 844 | + PUT1(0x02); PUT1(0x01); PUT1(0x01); |
| 845 | + PUT1(0x02); PUT1(0x01); PUT1(0x01); |
| 846 | + WRAP(sig, 0x30); |
| 847 | + } |
| 848 | + WRAP(s, 0x03); |
| 849 | + |
| 850 | + WRAP(0, 0x30); /* outer Certificate SEQUENCE */ |
| 851 | + } |
| 852 | + |
| 853 | + /* Parse the crafted certificate */ |
| 854 | + x = wolfSSL_X509_d2i(NULL, buf, (int)pos); |
| 855 | + ExpectNotNull(x); |
| 856 | + |
| 857 | + /* Attempt re-encode via i2d_X509_bio -- must fail gracefully, not |
| 858 | + * overflow. Before the fix this would write ~4000 bytes past the |
| 859 | + * end of cert->akid[]. */ |
| 860 | + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); |
| 861 | + ExpectNotNull(bio); |
| 862 | + ExpectIntEQ(wolfSSL_i2d_X509_bio(bio, x), 0); |
| 863 | + |
| 864 | + wolfSSL_BIO_free(bio); |
| 865 | + wolfSSL_X509_free(x); |
| 866 | + XFREE(akid_val, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| 867 | +#ifdef WOLFSSL_SMALL_STACK |
| 868 | + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
| 869 | +#endif |
| 870 | + |
| 871 | + #undef PUT1 |
| 872 | + #undef PUTN |
| 873 | + #undef TLV_HDR |
| 874 | + #undef WRAP |
| 875 | +#endif |
| 876 | + return EXPECT_RESULT(); |
| 877 | +} |
0 commit comments