From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: redhat.com, ip: 209.132.183.28, mailfrom: lersek@redhat.com) Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by groups.io with SMTP; Tue, 02 Jul 2019 03:29:07 -0700 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C7C1258E33; Tue, 2 Jul 2019 10:28:50 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-117-172.ams2.redhat.com [10.36.117.172]) by smtp.corp.redhat.com (Postfix) with ESMTP id 260201972C; Tue, 2 Jul 2019 10:28:48 +0000 (UTC) From: "Laszlo Ersek" To: edk2-devel-groups-io Cc: Liming Gao , =?UTF-8?q?Marvin=20H=C3=A4user?= , Michael D Kinney , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Zhichao Gao Subject: [PATCH 1/3] MdePkg/BaseLib: re-specify Base64Decode(), and add temporary stub impl Date: Tue, 2 Jul 2019 12:28:34 +0200 Message-Id: <20190702102836.27589-2-lersek@redhat.com> In-Reply-To: <20190702102836.27589-1-lersek@redhat.com> References: <20190702102836.27589-1-lersek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 02 Jul 2019 10:29:06 +0000 (UTC) Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Rewrite Base64Decode() from scratch, due to reasons listed in the second reference below. As first step, redo the interface contract, and replace the current implementation with a stub that asserts FALSE, then fails. Cc: Liming Gao Cc: Marvin H=C3=A4user Cc: Michael D Kinney Cc: Philippe Mathieu-Daud=C3=A9 Cc: Zhichao Gao Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3D1891 Ref: http://mid.mail-archive.com/c495bd0b-ea4d-7206-8a4f-a7149760d19a@red= hat.com Signed-off-by: Laszlo Ersek --- MdePkg/Include/Library/BaseLib.h | 99 +++++-- MdePkg/Library/BaseLib/String.c | 285 ++++++-------------- 2 files changed, 168 insertions(+), 216 deletions(-) diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/Ba= seLib.h index ebd7dd274cf4..5ef03e24edb1 100644 --- a/MdePkg/Include/Library/BaseLib.h +++ b/MdePkg/Include/Library/BaseLib.h @@ -2785,31 +2785,94 @@ Base64Encode ( ); =20 /** - Convert Base64 ascii string to binary data based on RFC4648. + Decode Base64 ASCII encoded data to 8-bit binary representation, based= on + RFC4648. =20 - Produce Null-terminated binary data in the output buffer specified by = Destination and DestinationSize. - The binary data is produced by converting the Base64 ascii string spec= ified by Source and SourceLength. + Decoding occurs according to "Table 1: The Base 64 Alphabet" in RFC464= 8. =20 - @param Source Input ASCII characters - @param SourceLength Number of ASCII characters - @param Destination Pointer to output buffer - @param DestinationSize Caller is responsible for passing in buffer of = at least DestinationSize. - Set 0 to get the size needed. Set to bytes stor= ed on return. + Whitespace is ignored at all positions: + - 0x09 ('\t') horizontal tab + - 0x0A ('\n') new line + - 0x0B ('\v') vertical tab + - 0x0C ('\f') form feed + - 0x0D ('\r') carriage return + - 0x20 (' ') space =20 - @retval RETURN_SUCCESS When binary buffer is filled in. - @retval RETURN_INVALID_PARAMETER If Source is NULL or DestinationSiz= e is NULL. - @retval RETURN_INVALID_PARAMETER If SourceLength or DestinationSize = is bigger than (MAX_ADDRESS -(UINTN)Destination ). - @retval RETURN_INVALID_PARAMETER If there is any invalid character i= n input stream. - @retval RETURN_BUFFER_TOO_SMALL If buffer length is smaller than re= quired buffer size. + The minimum amount of required padding (with ASCII 0x3D, '=3D') is tol= erated + and enforced at the end of the Base64 ASCII encoded data, and only the= re. =20 - **/ + Other characters outside of the encoding alphabet cause the function t= o + reject the Base64 ASCII encoded data. + + @param[in] Source Array of CHAR8 elements containing the= Base64 + ASCII encoding. May be NULL if SourceS= ize is + zero. + + @param[in] SourceSize Number of CHAR8 elements in Source. + + @param[out] Destination Array of UINT8 elements receiving the = decoded + 8-bit binary representation. Allocated= by the + caller. May be NULL if DestinationSize= is + zero on input. If NULL, decoding is + performed, but the 8-bit binary + representation is not stored. If non-N= ULL and + the function returns an error, the con= tents + of Destination are indeterminate. + + @param[in,out] DestinationSize On input, the number of UINT8 elements= that + the caller allocated for Destination. = On + output, if the function returns + RETURN_SUCCESS or RETURN_BUFFER_TOO_SM= ALL, + the number of UINT8 elements that are + required for decoding the Base64 ASCII + representation. If the function return= s a + value different from both RETURN_SUCCE= SS and + RETURN_BUFFER_TOO_SMALL, then Destinat= ionSize + is indeterminate on output. + + @retval RETURN_SUCCESS SourceSize CHAR8 elements at Source = have + been decoded to on-output Destinatio= nSize + UINT8 elements at Destination. Note = that + RETURN_SUCCESS covers the case when + DestinationSize is zero on input, an= d + Source decodes to zero bytes (due to + containing at most ignored whitespac= e). + + @retval RETURN_BUFFER_TOO_SMALL The input value of DestinationSize i= s not + large enough for decoding SourceSize= CHAR8 + elements at Source. The required num= ber of + UINT8 elements has been stored to + DestinationSize. + + @retval RETURN_INVALID_PARAMETER DestinationSize is NULL. + + @retval RETURN_INVALID_PARAMETER Source is NULL, but SourceSize is no= t zero. + + @retval RETURN_INVALID_PARAMETER Destination is NULL, but Destination= Size is + not zero on input. + + @retval RETURN_INVALID_PARAMETER Source is non-NULL, and (Source + + SourceSize) would wrap around MAX_AD= DRESS. + + @retval RETURN_INVALID_PARAMETER Destination is non-NULL, and (Destin= ation + + DestinationSize) would wrap around + MAX_ADDRESS, as specified on input. + + @retval RETURN_INVALID_PARAMETER None of Source and Destination are N= ULL, + and CHAR8[SourceSize] at Source over= laps + UINT8[DestinationSize] at Destinatio= n, as + specified on input. + + @retval RETURN_INVALID_PARAMETER Invalid CHAR8 element encountered in + Source. +**/ RETURN_STATUS EFIAPI Base64Decode ( - IN CONST CHAR8 *Source, - IN UINTN SourceLength, - OUT UINT8 *Destination OPTIONAL, - IN OUT UINTN *DestinationSize + IN CONST CHAR8 *Source OPTIONAL, + IN UINTN SourceSize, + OUT UINT8 *Destination OPTIONAL, + IN OUT UINTN *DestinationSize ); =20 /** diff --git a/MdePkg/Library/BaseLib/String.c b/MdePkg/Library/BaseLib/Str= ing.c index 32e189791cb8..f8397035c32a 100644 --- a/MdePkg/Library/BaseLib/String.c +++ b/MdePkg/Library/BaseLib/String.c @@ -1757,45 +1757,10 @@ AsciiStrToUnicodeStr ( =20 #endif =20 -// -// The basis for Base64 encoding is RFC 4686 https://tools.ietf.org/html= /rfc4648 -// -// RFC 4686 has a number of MAY and SHOULD cases. This implementation c= hooses -// the more restrictive versions for security concerns (see RFC 4686 sec= tion 3.3). -// -// A invalid character, if encountered during the decode operation, caus= es the data -// to be rejected. In addition, the '=3D' padding character is only allo= wed at the end -// of the Base64 encoded string. -// -#define BAD_V 99 - STATIC CHAR8 EncodingTable[] =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; =20 -STATIC UINT8 DecodingTable[] =3D { - // - // Valid characters ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx= yz0123456789+/ - // Also, set '=3D' as a zero for decoding - // 0 , 1, 2, 3, 4, = 5, 6, 7, 8, 9, a, = b, c, d, e, f - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // 0 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // 10 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, 62, BAD_V, BAD_V, BAD_V, 63, // 20 - 52, 53, 54, 55, 56, 57, 58, 59, 60,= 61, BAD_V, BAD_V, BAD_V, 0, BAD_V, BAD_V, // 30 - BAD_V, 0, 1, 2, 3, 4, 5, 6, 7,= 8, 9, 10, 11, 12, 13, 14, // 40 - 15, 16, 17, 18, 19, 20, 21, 22, 23,= 24, 25, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // 50 - BAD_V, 26, 27, 28, 29, 30, 31, 32, 33,= 34, 35, 36, 37, 38, 39, 40, // 60 - 41, 42, 43, 44, 45, 46, 47, 48, 49,= 50, 51, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // 70 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // 80 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // 90 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // a0 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // b0 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // c0 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // d0 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, // d0 - BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V,= BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V, BAD_V // f0 -}; - /** Convert binary data to a Base64 encoded ascii string based on RFC4648. =20 @@ -1918,174 +1883,98 @@ Base64Encode ( } =20 /** - Convert Base64 ascii string to binary data based on RFC4648. - - Produce Null-terminated binary data in the output buffer specified by = Destination and DestinationSize. - The binary data is produced by converting the Base64 ascii string spec= ified by Source and SourceLength. - - @param Source Input ASCII characters - @param SourceLength Number of ASCII characters - @param Destination Pointer to output buffer - @param DestinationSize Caller is responsible for passing in buffer o= f at least DestinationSize. - Set 0 to get the size needed. Set to bytes st= ored on return. - - @retval RETURN_SUCCESS When binary buffer is filled in. - @retval RETURN_INVALID_PARAMETER If Source is NULL or DestinationSiz= e is NULL. - @retval RETURN_INVALID_PARAMETER If SourceLength or DestinationSize = is bigger than (MAX_ADDRESS -(UINTN)Destination ). - @retval RETURN_INVALID_PARAMETER If there is any invalid character i= n input stream. - @retval RETURN_BUFFER_TOO_SMALL If buffer length is smaller than re= quired buffer size. - **/ + Decode Base64 ASCII encoded data to 8-bit binary representation, based= on + RFC4648. + + Decoding occurs according to "Table 1: The Base 64 Alphabet" in RFC464= 8. + + Whitespace is ignored at all positions: + - 0x09 ('\t') horizontal tab + - 0x0A ('\n') new line + - 0x0B ('\v') vertical tab + - 0x0C ('\f') form feed + - 0x0D ('\r') carriage return + - 0x20 (' ') space + + The minimum amount of required padding (with ASCII 0x3D, '=3D') is tol= erated + and enforced at the end of the Base64 ASCII encoded data, and only the= re. + + Other characters outside of the encoding alphabet cause the function t= o + reject the Base64 ASCII encoded data. + + @param[in] Source Array of CHAR8 elements containing the= Base64 + ASCII encoding. May be NULL if SourceS= ize is + zero. + + @param[in] SourceSize Number of CHAR8 elements in Source. + + @param[out] Destination Array of UINT8 elements receiving the = decoded + 8-bit binary representation. Allocated= by the + caller. May be NULL if DestinationSize= is + zero on input. If NULL, decoding is + performed, but the 8-bit binary + representation is not stored. If non-N= ULL and + the function returns an error, the con= tents + of Destination are indeterminate. + + @param[in,out] DestinationSize On input, the number of UINT8 elements= that + the caller allocated for Destination. = On + output, if the function returns + RETURN_SUCCESS or RETURN_BUFFER_TOO_SM= ALL, + the number of UINT8 elements that are + required for decoding the Base64 ASCII + representation. If the function return= s a + value different from both RETURN_SUCCE= SS and + RETURN_BUFFER_TOO_SMALL, then Destinat= ionSize + is indeterminate on output. + + @retval RETURN_SUCCESS SourceSize CHAR8 elements at Source = have + been decoded to on-output Destinatio= nSize + UINT8 elements at Destination. Note = that + RETURN_SUCCESS covers the case when + DestinationSize is zero on input, an= d + Source decodes to zero bytes (due to + containing at most ignored whitespac= e). + + @retval RETURN_BUFFER_TOO_SMALL The input value of DestinationSize i= s not + large enough for decoding SourceSize= CHAR8 + elements at Source. The required num= ber of + UINT8 elements has been stored to + DestinationSize. + + @retval RETURN_INVALID_PARAMETER DestinationSize is NULL. + + @retval RETURN_INVALID_PARAMETER Source is NULL, but SourceSize is no= t zero. + + @retval RETURN_INVALID_PARAMETER Destination is NULL, but Destination= Size is + not zero on input. + + @retval RETURN_INVALID_PARAMETER Source is non-NULL, and (Source + + SourceSize) would wrap around MAX_AD= DRESS. + + @retval RETURN_INVALID_PARAMETER Destination is non-NULL, and (Destin= ation + + DestinationSize) would wrap around + MAX_ADDRESS, as specified on input. + + @retval RETURN_INVALID_PARAMETER None of Source and Destination are N= ULL, + and CHAR8[SourceSize] at Source over= laps + UINT8[DestinationSize] at Destinatio= n, as + specified on input. + + @retval RETURN_INVALID_PARAMETER Invalid CHAR8 element encountered in + Source. +**/ RETURN_STATUS EFIAPI Base64Decode ( - IN CONST CHAR8 *Source, - IN UINTN SourceLength, - OUT UINT8 *Destination OPTIONAL, - IN OUT UINTN *DestinationSize + IN CONST CHAR8 *Source OPTIONAL, + IN UINTN SourceSize, + OUT UINT8 *Destination OPTIONAL, + IN OUT UINTN *DestinationSize ) { - - UINT32 Value; - CHAR8 Chr; - INTN BufferSize; - UINTN SourceIndex; - UINTN DestinationIndex; - UINTN Index; - UINTN ActualSourceLength; - - // - // Check pointers are not NULL - // - if ((Source =3D=3D NULL) || (DestinationSize =3D=3D NULL)) { - return RETURN_INVALID_PARAMETER; - } - - // - // Check if SourceLength or DestinationSize is valid - // - if ((SourceLength >=3D (MAX_ADDRESS - (UINTN)Source)) || (*Destination= Size >=3D (MAX_ADDRESS - (UINTN)Destination))){ - return RETURN_INVALID_PARAMETER; - } - - ActualSourceLength =3D 0; - BufferSize =3D 0; - - // - // Determine the actual number of valid characters in the string. - // All invalid characters except selected white space characters, - // will cause the Base64 string to be rejected. White space to allow - // properly formatted XML will be ignored. - // - // See section 3.3 of RFC 4648. - // - for (SourceIndex =3D 0; SourceIndex < SourceLength; SourceIndex++) { - - // - // '=3D' is part of the quantum - // - if (Source[SourceIndex] =3D=3D '=3D') { - ActualSourceLength++; - BufferSize--; - - // - // Only two '=3D' characters can be valid. - // - if (BufferSize < -2) { - return RETURN_INVALID_PARAMETER; - } - } - else { - Chr =3D Source[SourceIndex]; - if (BAD_V !=3D DecodingTable[(UINT8) Chr]) { - - // - // The '=3D' characters are only valid at the end, so any - // valid character after an '=3D', will be flagged as an error. - // - if (BufferSize < 0) { - return RETURN_INVALID_PARAMETER; - } - ActualSourceLength++; - } - else { - - // - // The reset of the decoder will ignore all invalid characters a= llowed here. - // Ignoring selected white space is useful. In this case, the d= ecoder will - // ignore ' ', '\t', '\n', and '\r'. - // - if ((Chr !=3D ' ') &&(Chr !=3D '\t') &&(Chr !=3D '\n') &&(Chr !=3D= '\r')) { - return RETURN_INVALID_PARAMETER; - } - } - } - } - - // - // The Base64 character string must be a multiple of 4 character quant= ums. - // - if (ActualSourceLength % 4 !=3D 0) { - return RETURN_INVALID_PARAMETER; - } - - BufferSize +=3D ActualSourceLength / 4 * 3; - if (BufferSize < 0) { - return RETURN_INVALID_PARAMETER; - } - - // - // BufferSize is >=3D 0 - // - if ((Destination =3D=3D NULL) || (*DestinationSize < (UINTN) BufferSiz= e)) { - *DestinationSize =3D BufferSize; - return RETURN_BUFFER_TOO_SMALL; - } - - // - // If no decodable characters, return a size of zero. RFC 4686 test ve= ctor 1. - // - if (ActualSourceLength =3D=3D 0) { - *DestinationSize =3D 0; - return RETURN_SUCCESS; - } - - // - // Input data is verified to be a multiple of 4 valid charcters. Proc= ess four - // characters at a time. Uncounted (ie. invalid) characters will be i= gnored. - // - for (SourceIndex =3D 0, DestinationIndex =3D 0; (SourceIndex < SourceL= ength) && (DestinationIndex < *DestinationSize); ) { - Value =3D 0; - - // - // Get 24 bits of data from 4 input characters, each character repre= senting 6 bits - // - for (Index =3D 0; Index < 4; Index++) { - do { - Chr =3D DecodingTable[(UINT8) Source[SourceIndex++]]; - } while (Chr =3D=3D BAD_V); - Value <<=3D 6; - Value |=3D (UINT32)Chr; - } - - // - // Store 3 bytes of binary data (24 bits) - // - *Destination++ =3D (UINT8) (Value >> 16); - DestinationIndex++; - - // - // Due to the '=3D' special cases for the two bytes at the end, - // we have to check the length and not store the padding data - // - if (DestinationIndex++ < *DestinationSize) { - *Destination++ =3D (UINT8) (Value >> 8); - } - if (DestinationIndex++ < *DestinationSize) { - *Destination++ =3D (UINT8) Value; - } - } - - return RETURN_SUCCESS; + ASSERT (FALSE); + return RETURN_INVALID_PARAMETER; } =20 /** --=20 2.19.1.3.g30247aa5d201