|
| 1 | +From: Viktor Dukhovni <openssl-users@dukhovni.org> |
| 2 | +Date: Tue, 7 Apr 2026 22:40:55 +1000 |
| 3 | +Subject: Avoid length truncation in ASN1_STRING_set |
| 4 | + |
| 5 | +The ASN1_STRING_set() function takes an `int` length, make sure the |
| 6 | +argument is not inadvertently truncated when it is called from |
| 7 | +asn1_ex_c2i(). |
| 8 | + |
| 9 | +Fixes CVE-2026-34180 |
| 10 | + |
| 11 | +Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org> |
| 12 | +Reviewed-by: Norbert Pocs <norbertp@openssl.org> |
| 13 | +Reviewed-by: Tomas Mraz <tomas@openssl.foundation> |
| 14 | +MergeDate: Mon Jun 8 14:13:56 2026 |
| 15 | +(cherry picked from commit 5f525cace61a53311ee533374919356c700847d9) |
| 16 | +--- |
| 17 | + crypto/asn1/tasn_dec.c | 24 +++++++++++++++++------- |
| 18 | + 1 file changed, 17 insertions(+), 7 deletions(-) |
| 19 | + |
| 20 | +diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c |
| 21 | +index 91c2e524f55b9..e9532b9f48f74 100644 |
| 22 | +--- a/crypto/asn1/tasn_dec.c |
| 23 | ++++ b/crypto/asn1/tasn_dec.c |
| 24 | +@@ -54,7 +54,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, |
| 25 | + const ASN1_ITEM *it, |
| 26 | + int tag, int aclass, char opt, |
| 27 | + ASN1_TLC *ctx); |
| 28 | +-static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, |
| 29 | ++static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, long len, |
| 30 | + int utype, char *free_cont, const ASN1_ITEM *it); |
| 31 | + |
| 32 | + /* Table to convert tags to bit values, used for MSTRING type */ |
| 33 | +@@ -855,19 +855,24 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, |
| 34 | + |
| 35 | + /* Translate ASN1 content octets into a structure */ |
| 36 | + |
| 37 | +-static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, |
| 38 | ++static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, long len, |
| 39 | + int utype, char *free_cont, const ASN1_ITEM *it) |
| 40 | + { |
| 41 | + ASN1_VALUE **opval = NULL; |
| 42 | + ASN1_STRING *stmp; |
| 43 | + ASN1_TYPE *typ = NULL; |
| 44 | + int ret = 0; |
| 45 | ++ int ilen = (int)len; |
| 46 | + const ASN1_PRIMITIVE_FUNCS *pf; |
| 47 | + ASN1_INTEGER **tint; |
| 48 | + pf = it->funcs; |
| 49 | + |
| 50 | +- if (pf && pf->prim_c2i) |
| 51 | +- return pf->prim_c2i(pval, cont, len, utype, free_cont, it); |
| 52 | ++ if (pf && pf->prim_c2i) { |
| 53 | ++ if (len == (long)ilen) |
| 54 | ++ return pf->prim_c2i(pval, cont, ilen, utype, free_cont, it); |
| 55 | ++ ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); |
| 56 | ++ return 0; |
| 57 | ++ } |
| 58 | + /* If ANY type clear type and set pointer to internal value */ |
| 59 | + if (it->utype == V_ASN1_ANY) { |
| 60 | + if (*pval == NULL) { |
| 61 | +@@ -885,7 +890,8 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, |
| 62 | + } |
| 63 | + switch (utype) { |
| 64 | + case V_ASN1_OBJECT: |
| 65 | +- if (!ossl_c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) |
| 66 | ++ if (len != (long)ilen |
| 67 | ++ || !ossl_c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, ilen)) |
| 68 | + goto err; |
| 69 | + break; |
| 70 | + |
| 71 | +@@ -940,6 +946,10 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, |
| 72 | + case V_ASN1_SET: |
| 73 | + case V_ASN1_SEQUENCE: |
| 74 | + default: |
| 75 | ++ if (len != (long)ilen) { |
| 76 | ++ ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); |
| 77 | ++ goto err; |
| 78 | ++ } |
| 79 | + if (utype == V_ASN1_BMPSTRING && (len & 1)) { |
| 80 | + ERR_raise(ERR_LIB_ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH); |
| 81 | + goto err; |
| 82 | +@@ -970,10 +980,10 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, |
| 83 | + } |
| 84 | + /* If we've already allocated a buffer use it */ |
| 85 | + if (*free_cont) { |
| 86 | +- ASN1_STRING_set0(stmp, (unsigned char *)cont /* UGLY CAST! */, len); |
| 87 | ++ ASN1_STRING_set0(stmp, (unsigned char *)cont /* UGLY CAST! */, ilen); |
| 88 | + *free_cont = 0; |
| 89 | + } else { |
| 90 | +- if (!ASN1_STRING_set(stmp, cont, len)) { |
| 91 | ++ if (!ASN1_STRING_set(stmp, cont, ilen)) { |
| 92 | + ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); |
| 93 | + ASN1_STRING_free(stmp); |
| 94 | + *pval = NULL; |
0 commit comments