summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2022-05-17 19:09:16 +0000
committerjsing <>2022-05-17 19:09:16 +0000
commit422d86c6404e0488f549a5e1def8849243e656c6 (patch)
tree676a4511890618bc9cee65df2e48c88fd13a907b /src
parent440516cf733a3d776a7133a827812490af8d75e1 (diff)
downloadopenbsd-422d86c6404e0488f549a5e1def8849243e656c6.tar.gz
openbsd-422d86c6404e0488f549a5e1def8849243e656c6.tar.bz2
openbsd-422d86c6404e0488f549a5e1def8849243e656c6.zip
Refactor asn1_d2i_ex_primitive()
Split the object content handling off into asn1_d2i_ex_primitive_content(), move the handling ov V_ASN1_ANY into asn1_d2i_ex_any() and move the MSTRING handling into asn1_d2i_ex_mstring(). This way we parse the header once (rather than twice for ANY and MSTRING), then process the content, while also avoiding complex special cases in a single code path. ok tb@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/asn1/tasn_dec.c244
1 files changed, 146 insertions, 98 deletions
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c
index 88b61a997d..234484d6b2 100644
--- a/src/lib/libcrypto/asn1/tasn_dec.c
+++ b/src/lib/libcrypto/asn1/tasn_dec.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tasn_dec.c,v 1.69 2022/05/17 12:23:52 jsing Exp $ */ 1/* $OpenBSD: tasn_dec.c,v 1.70 2022/05/17 19:09:16 jsing Exp $ */
2/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 2/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3 * project 2000. 3 * project 2000.
4 */ 4 */
@@ -91,6 +91,8 @@ static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
91 long len, const ASN1_TEMPLATE *tt, char opt, int depth); 91 long len, const ASN1_TEMPLATE *tt, char opt, int depth);
92static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, 92static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in,
93 long len, const ASN1_TEMPLATE *tt, char opt, int depth); 93 long len, const ASN1_TEMPLATE *tt, char opt, int depth);
94static int asn1_d2i_ex_mstring(ASN1_VALUE **pval, CBS *CBS,
95 const ASN1_ITEM *it, int tag_number, int tag_class, char optional);
94static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, 96static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs,
95 const ASN1_ITEM *it, int tag_number, int tag_class, char optional); 97 const ASN1_ITEM *it, int tag_number, int tag_class, char optional);
96static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, 98static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype,
@@ -399,9 +401,6 @@ asn1_item_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
399 const ASN1_EXTERN_FUNCS *ef = it->funcs; 401 const ASN1_EXTERN_FUNCS *ef = it->funcs;
400 const unsigned char *p = NULL; 402 const unsigned char *p = NULL;
401 ASN1_TLC ctx = { 0 }; 403 ASN1_TLC ctx = { 0 };
402 CBS cbs_mstring;
403 unsigned char oclass;
404 int otag;
405 int ret = 0; 404 int ret = 0;
406 405
407 if (pval == NULL) 406 if (pval == NULL)
@@ -433,39 +432,8 @@ asn1_item_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
433 tag_class, optional); 432 tag_class, optional);
434 433
435 case ASN1_ITYPE_MSTRING: 434 case ASN1_ITYPE_MSTRING:
436 /* 435 return asn1_d2i_ex_mstring(pval, cbs, it, tag_number, tag_class,
437 * It never makes sense for multi-strings to have implicit 436 optional);
438 * tagging, so if tag != -1, then this looks like an error in
439 * the template.
440 */
441 if (tag_number != -1) {
442 ASN1error(ASN1_R_BAD_TEMPLATE);
443 goto err;
444 }
445
446 /* XXX - avoid reading the header twice for MSTRING. */
447 CBS_dup(cbs, &cbs_mstring);
448 if (asn1_check_tag_cbs(&cbs_mstring, NULL, &otag, &oclass,
449 NULL, NULL, -1, 0, 1) != 1) {
450 ASN1error(ERR_R_NESTED_ASN1_ERROR);
451 goto err;
452 }
453
454 /* Must be UNIVERSAL class */
455 if (oclass != V_ASN1_UNIVERSAL) {
456 if (optional)
457 return -1;
458 ASN1error(ASN1_R_MSTRING_NOT_UNIVERSAL);
459 goto err;
460 }
461 /* Check tag matches bit map */
462 if (!(ASN1_tag2bit(otag) & it->utype)) {
463 if (optional)
464 return -1;
465 ASN1error(ASN1_R_MSTRING_WRONG_TAG);
466 goto err;
467 }
468 return asn1_d2i_ex_primitive(pval, cbs, it, otag, 0, 0);
469 437
470 case ASN1_ITYPE_EXTERN: 438 case ASN1_ITYPE_EXTERN:
471 if (CBS_len(cbs) > LONG_MAX) 439 if (CBS_len(cbs) > LONG_MAX)
@@ -750,74 +718,35 @@ asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len,
750 return 0; 718 return 0;
751} 719}
752 720
721/*
722 * Decode ASN.1 content into a primitive type. There are three possible forms -
723 * a SEQUENCE/SET/OTHER that is stored verbatim (including the ASN.1 tag and
724 * length octets), constructed objects and non-constructed objects. In the
725 * first two cases indefinite length is permitted, which we may need to handle.
726 * When this function is called the *cbs should reference the start of the
727 * ASN.1 object (i.e. the tag/length header), while *cbs_object should
728 * reference the start of the object contents (i.e. after the tag/length
729 * header. Additionally, the *cbs_object offset should be relative to the
730 * ASN.1 object being parsed. On success the *cbs will point at the octet
731 * after the object.
732 */
753static int 733static int
754asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, 734asn1_d2i_ex_primitive_content(ASN1_VALUE **pval, CBS *cbs, CBS *cbs_object,
755 int tag_number, int tag_class, char optional) 735 int utype, char constructed, char indefinite, size_t length,
736 const ASN1_ITEM *it)
756{ 737{
757 CBS cbs_any, cbs_content, cbs_object, cbs_initial; 738 CBS cbs_content, cbs_initial;
758 char constructed, indefinite;
759 uint8_t *data = NULL; 739 uint8_t *data = NULL;
760 size_t data_len = 0; 740 size_t data_len = 0;
761 int utype = it->utype;
762 unsigned char oclass;
763 size_t length;
764 CBB cbb; 741 CBB cbb;
765 int tag_ret;
766 int ret = 0; 742 int ret = 0;
767 743
768 memset(&cbb, 0, sizeof(cbb)); 744 memset(&cbb, 0, sizeof(cbb));
769 745
770 CBS_dup(cbs, &cbs_initial); 746 CBS_dup(cbs, &cbs_initial);
771 CBS_init(&cbs_content, NULL, 0); 747 CBS_init(&cbs_content, NULL, 0);
772 CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs));
773
774 if (pval == NULL) {
775 ASN1error(ASN1_R_ILLEGAL_NULL);
776 goto err;
777 }
778
779 if (it->itype == ASN1_ITYPE_MSTRING) {
780 utype = tag_number;
781 tag_number = -1;
782 }
783
784 if (utype == V_ASN1_ANY) {
785 /* Determine type from ASN.1 tag. */
786 if (tag_number >= 0) {
787 ASN1error(ASN1_R_ILLEGAL_TAGGED_ANY);
788 goto err;
789 }
790 if (optional) {
791 ASN1error(ASN1_R_ILLEGAL_OPTIONAL_ANY);
792 goto err;
793 }
794 /* XXX - avoid reading the header twice for ANY. */
795 CBS_dup(&cbs_object, &cbs_any);
796 tag_ret = asn1_check_tag_cbs(&cbs_any, NULL, &utype, &oclass,
797 NULL, NULL, -1, 0, 0);
798 if (tag_ret != 1) {
799 ASN1error(ERR_R_NESTED_ASN1_ERROR);
800 goto err;
801 }
802 if (oclass != V_ASN1_UNIVERSAL)
803 utype = V_ASN1_OTHER;
804 }
805 748
806 if (tag_number == -1) { 749 /* XXX - check primitive vs constructed based on utype. */
807 tag_number = utype;
808 tag_class = V_ASN1_UNIVERSAL;
809 }
810
811 tag_ret = asn1_check_tag_cbs(&cbs_object, &length, NULL, NULL, &indefinite,
812 &constructed, tag_number, tag_class, optional);
813 if (tag_ret == -1) {
814 ret = -1;
815 goto err;
816 }
817 if (tag_ret != 1) {
818 ASN1error(ERR_R_NESTED_ASN1_ERROR);
819 goto err;
820 }
821 750
822 /* SEQUENCE and SET must be constructed. */ 751 /* SEQUENCE and SET must be constructed. */
823 if ((utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET) && !constructed) { 752 if ((utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET) && !constructed) {
@@ -828,10 +757,10 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
828 /* SEQUENCE, SET and "OTHER" are left in encoded form. */ 757 /* SEQUENCE, SET and "OTHER" are left in encoded form. */
829 if (utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET || 758 if (utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET ||
830 utype == V_ASN1_OTHER) { 759 utype == V_ASN1_OTHER) {
831 if (!asn1_find_end(&cbs_object, length, indefinite)) 760 if (!asn1_find_end(cbs_object, length, indefinite))
832 goto err; 761 goto err;
833 if (!CBS_get_bytes(&cbs_initial, &cbs_content, 762 if (!CBS_get_bytes(&cbs_initial, &cbs_content,
834 CBS_offset(&cbs_object))) 763 CBS_offset(cbs_object)))
835 goto err; 764 goto err;
836 } else if (constructed) { 765 } else if (constructed) {
837 /* 766 /*
@@ -843,7 +772,7 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
843 */ 772 */
844 if (!CBB_init(&cbb, 0)) 773 if (!CBB_init(&cbb, 0))
845 goto err; 774 goto err;
846 if (!asn1_collect(&cbb, &cbs_object, indefinite, -1, 775 if (!asn1_collect(&cbb, cbs_object, indefinite, -1,
847 V_ASN1_UNIVERSAL, 0)) 776 V_ASN1_UNIVERSAL, 0))
848 goto err; 777 goto err;
849 if (!CBB_finish(&cbb, &data, &data_len)) 778 if (!CBB_finish(&cbb, &data, &data_len))
@@ -851,14 +780,14 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
851 780
852 CBS_init(&cbs_content, data, data_len); 781 CBS_init(&cbs_content, data, data_len);
853 } else { 782 } else {
854 if (!CBS_get_bytes(&cbs_object, &cbs_content, length)) 783 if (!CBS_get_bytes(cbs_object, &cbs_content, length))
855 goto err; 784 goto err;
856 } 785 }
857 786
858 if (!asn1_ex_c2i(pval, &cbs_content, utype, it)) 787 if (!asn1_ex_c2i(pval, &cbs_content, utype, it))
859 goto err; 788 goto err;
860 789
861 if (!CBS_skip(cbs, CBS_offset(&cbs_object))) 790 if (!CBS_skip(cbs, CBS_offset(cbs_object)))
862 goto err; 791 goto err;
863 792
864 ret = 1; 793 ret = 1;
@@ -871,6 +800,125 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
871} 800}
872 801
873static int 802static int
803asn1_d2i_ex_any(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
804 int tag_number, int tag_class, char optional)
805{
806 char constructed, indefinite;
807 unsigned char object_class;
808 int object_type;
809 CBS cbs_object;
810 size_t length;
811
812 CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs));
813
814 if (it->utype != V_ASN1_ANY)
815 return 0;
816
817 if (tag_number >= 0) {
818 ASN1error(ASN1_R_ILLEGAL_TAGGED_ANY);
819 return 0;
820 }
821 if (optional) {
822 ASN1error(ASN1_R_ILLEGAL_OPTIONAL_ANY);
823 return 0;
824 }
825
826 /* Determine type from ASN.1 tag. */
827 if (asn1_check_tag_cbs(&cbs_object, &length, &object_type, &object_class,
828 &indefinite, &constructed, -1, 0, 0) != 1) {
829 ASN1error(ERR_R_NESTED_ASN1_ERROR);
830 return 0;
831 }
832 if (object_class != V_ASN1_UNIVERSAL)
833 object_type = V_ASN1_OTHER;
834
835 return asn1_d2i_ex_primitive_content(pval, cbs, &cbs_object, object_type,
836 constructed, indefinite, length, it);
837}
838
839static int
840asn1_d2i_ex_mstring(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
841 int tag_number, int tag_class, char optional)
842{
843 char constructed, indefinite;
844 unsigned char object_class;
845 int object_tag;
846 CBS cbs_object;
847 size_t length;
848
849 CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs));
850
851 /*
852 * It never makes sense for multi-strings to have implicit tagging, so
853 * if tag_number != -1, then this looks like an error in the template.
854 */
855 if (tag_number != -1) {
856 ASN1error(ASN1_R_BAD_TEMPLATE);
857 return 0;
858 }
859
860 if (asn1_check_tag_cbs(&cbs_object, &length, &object_tag, &object_class,
861 &indefinite, &constructed, -1, 0, 1) != 1) {
862 ASN1error(ERR_R_NESTED_ASN1_ERROR);
863 return 0;
864 }
865
866 /* Class must be UNIVERSAL. */
867 if (object_class != V_ASN1_UNIVERSAL) {
868 if (optional)
869 return -1;
870 ASN1error(ASN1_R_MSTRING_NOT_UNIVERSAL);
871 return 0;
872 }
873 /* Check tag matches bit map. */
874 if ((ASN1_tag2bit(object_tag) & it->utype) == 0) {
875 if (optional)
876 return -1;
877 ASN1error(ASN1_R_MSTRING_WRONG_TAG);
878 return 0;
879 }
880
881 return asn1_d2i_ex_primitive_content(pval, cbs, &cbs_object,
882 object_tag, constructed, indefinite, length, it);
883}
884
885static int
886asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
887 int tag_number, int tag_class, char optional)
888{
889 CBS cbs_object;
890 char constructed, indefinite;
891 int utype = it->utype;
892 size_t length;
893 int ret;
894
895 CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs));
896
897 if (it->itype == ASN1_ITYPE_MSTRING)
898 return 0;
899
900 if (it->utype == V_ASN1_ANY)
901 return asn1_d2i_ex_any(pval, cbs, it, tag_number, tag_class, optional);
902
903 if (tag_number == -1) {
904 tag_number = it->utype;
905 tag_class = V_ASN1_UNIVERSAL;
906 }
907
908 ret = asn1_check_tag_cbs(&cbs_object, &length, NULL, NULL, &indefinite,
909 &constructed, tag_number, tag_class, optional);
910 if (ret == -1)
911 return -1;
912 if (ret != 1) {
913 ASN1error(ERR_R_NESTED_ASN1_ERROR);
914 return 0;
915 }
916
917 return asn1_d2i_ex_primitive_content(pval, cbs, &cbs_object, utype,
918 constructed, indefinite, length, it);
919}
920
921static int
874asn1_ex_c2i_primitive(ASN1_VALUE **pval, CBS *content, int utype, const ASN1_ITEM *it) 922asn1_ex_c2i_primitive(ASN1_VALUE **pval, CBS *content, int utype, const ASN1_ITEM *it)
875{ 923{
876 ASN1_STRING *stmp; 924 ASN1_STRING *stmp;