diff --git a/CryptoPkg/Include/Library/TlsLib.h b/CryptoPkg/Include/Library/TlsLib.h index e19a38a214..e71291eaea 100644 --- a/CryptoPkg/Include/Library/TlsLib.h +++ b/CryptoPkg/Include/Library/TlsLib.h @@ -348,13 +348,16 @@ TlsSetConnectionEnd ( This function sets the ciphers for use by a specified TLS object. @param[in] Tls Pointer to a TLS object. - @param[in] CipherId Pointer to a string that contains one or more - ciphers separated by a colon. + @param[in] CipherId Array of UINT16 cipher identifiers. Each UINT16 + cipher identifier comes from the TLS Cipher Suite + Registry of the IANA, interpreting Byte1 and Byte2 + in network (big endian) byte order. @param[in] CipherNum The number of cipher in the list. @retval EFI_SUCCESS The ciphers list was set successfully. @retval EFI_INVALID_PARAMETER The parameter is invalid. - @retval EFI_UNSUPPORTED Unsupported TLS cipher in the list. + @retval EFI_UNSUPPORTED No supported TLS cipher was found in CipherId. + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. **/ EFI_STATUS diff --git a/CryptoPkg/Library/TlsLib/InternalTlsLib.h b/CryptoPkg/Library/TlsLib/InternalTlsLib.h index 3f18a461a8..b6cf9816aa 100644 --- a/CryptoPkg/Library/TlsLib/InternalTlsLib.h +++ b/CryptoPkg/Library/TlsLib/InternalTlsLib.h @@ -19,9 +19,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #undef _WIN64 #include -#include #include #include +#include +#include #include #include #include diff --git a/CryptoPkg/Library/TlsLib/TlsConfig.c b/CryptoPkg/Library/TlsLib/TlsConfig.c index e2f819b903..9154686610 100644 --- a/CryptoPkg/Library/TlsLib/TlsConfig.c +++ b/CryptoPkg/Library/TlsLib/TlsConfig.c @@ -235,12 +235,16 @@ TlsSetConnectionEnd ( This function sets the ciphers for use by a specified TLS object. @param[in] Tls Pointer to a TLS object. - @param[in] CipherId Pointer to a UINT16 cipher Id. + @param[in] CipherId Array of UINT16 cipher identifiers. Each UINT16 + cipher identifier comes from the TLS Cipher Suite + Registry of the IANA, interpreting Byte1 and Byte2 + in network (big endian) byte order. @param[in] CipherNum The number of cipher in the list. @retval EFI_SUCCESS The ciphers list was set successfully. @retval EFI_INVALID_PARAMETER The parameter is invalid. - @retval EFI_UNSUPPORTED Unsupported TLS cipher in the list. + @retval EFI_UNSUPPORTED No supported TLS cipher was found in CipherId. + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. **/ EFI_STATUS @@ -252,51 +256,173 @@ TlsSetCipherList ( ) { TLS_CONNECTION *TlsConn; + EFI_STATUS Status; + CONST TLS_CIPHER_MAPPING **MappedCipher; + UINTN MappedCipherBytes; + UINTN MappedCipherCount; + UINTN CipherStringSize; UINTN Index; CONST TLS_CIPHER_MAPPING *Mapping; - CONST CHAR8 *MappingName; - CHAR8 CipherString[500]; + CHAR8 *CipherString; + CHAR8 *CipherStringPosition; TlsConn = (TLS_CONNECTION *) Tls; if (TlsConn == NULL || TlsConn->Ssl == NULL || CipherId == NULL) { return EFI_INVALID_PARAMETER; } - Mapping = NULL; - MappingName = NULL; - - memset (CipherString, 0, sizeof (CipherString)); - - for (Index = 0; Index < CipherNum; Index++) { - // - // Handling OpenSSL / RFC Cipher name mapping. - // - Mapping = TlsGetCipherMapping (*(CipherId + Index)); - if (Mapping == NULL) { - return EFI_UNSUPPORTED; - } - MappingName = Mapping->OpensslCipher; - - if (Index != 0) { - // - // The ciphers were separated by a colon. - // - AsciiStrCatS (CipherString, sizeof (CipherString), ":"); - } - - AsciiStrCatS (CipherString, sizeof (CipherString), MappingName); + // + // Allocate the MappedCipher array for recording the mappings that we find + // for the input IANA identifiers in CipherId. + // + Status = SafeUintnMult (CipherNum, sizeof (*MappedCipher), + &MappedCipherBytes); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + MappedCipher = AllocatePool (MappedCipherBytes); + if (MappedCipher == NULL) { + return EFI_OUT_OF_RESOURCES; } - AsciiStrCatS (CipherString, sizeof (CipherString), ":@STRENGTH"); + // + // Map the cipher IDs, and count the number of bytes for the full + // CipherString. + // + MappedCipherCount = 0; + CipherStringSize = 0; + for (Index = 0; Index < CipherNum; Index++) { + // + // Look up the IANA-to-OpenSSL mapping. + // + Mapping = TlsGetCipherMapping (CipherId[Index]); + if (Mapping == NULL) { + DEBUG ((DEBUG_VERBOSE, "%a:%a: skipping CipherId=0x%04x\n", + gEfiCallerBaseName, __FUNCTION__, CipherId[Index])); + // + // Skipping the cipher is valid because CipherId is an ordered + // preference list of ciphers, thus we can filter it as long as we + // don't change the relative order of elements on it. + // + continue; + } + // + // Accumulate Mapping->OpensslCipherLength into CipherStringSize. If this + // is not the first successful mapping, account for a colon (":") prefix + // too. + // + if (MappedCipherCount > 0) { + Status = SafeUintnAdd (CipherStringSize, 1, &CipherStringSize); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMappedCipher; + } + } + Status = SafeUintnAdd (CipherStringSize, Mapping->OpensslCipherLength, + &CipherStringSize); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMappedCipher; + } + // + // Record the mapping. + // + MappedCipher[MappedCipherCount++] = Mapping; + } + + // + // Verify that at least one IANA cipher ID could be mapped; account for the + // terminating NUL character in CipherStringSize; allocate CipherString. + // + if (MappedCipherCount == 0) { + DEBUG ((DEBUG_ERROR, "%a:%a: no CipherId could be mapped\n", + gEfiCallerBaseName, __FUNCTION__)); + Status = EFI_UNSUPPORTED; + goto FreeMappedCipher; + } + Status = SafeUintnAdd (CipherStringSize, 1, &CipherStringSize); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMappedCipher; + } + CipherString = AllocatePool (CipherStringSize); + if (CipherString == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMappedCipher; + } + + // + // Go over the collected mappings and populate CipherString. + // + CipherStringPosition = CipherString; + for (Index = 0; Index < MappedCipherCount; Index++) { + Mapping = MappedCipher[Index]; + // + // Append the colon (":") prefix except for the first mapping, then append + // Mapping->OpensslCipher. + // + if (Index > 0) { + *(CipherStringPosition++) = ':'; + } + CopyMem (CipherStringPosition, Mapping->OpensslCipher, + Mapping->OpensslCipherLength); + CipherStringPosition += Mapping->OpensslCipherLength; + } + + // + // NUL-terminate CipherString. + // + *(CipherStringPosition++) = '\0'; + ASSERT (CipherStringPosition == CipherString + CipherStringSize); + + // + // Log CipherString for debugging. CipherString can be very long if the + // caller provided a large CipherId array, so log CipherString in segments of + // 79 non-newline characters. (MAX_DEBUG_MESSAGE_LENGTH is usually 0x100 in + // DebugLib instances.) + // + DEBUG_CODE ( + UINTN FullLength; + UINTN SegmentLength; + + FullLength = CipherStringSize - 1; + DEBUG ((DEBUG_VERBOSE, "%a:%a: CipherString={\n", gEfiCallerBaseName, + __FUNCTION__)); + for (CipherStringPosition = CipherString; + CipherStringPosition < CipherString + FullLength; + CipherStringPosition += SegmentLength) { + SegmentLength = FullLength - (CipherStringPosition - CipherString); + if (SegmentLength > 79) { + SegmentLength = 79; + } + DEBUG ((DEBUG_VERBOSE, "%.*a\n", SegmentLength, CipherStringPosition)); + } + DEBUG ((DEBUG_VERBOSE, "}\n")); + // + // Restore the pre-debug value of CipherStringPosition by skipping over the + // trailing NUL. + // + CipherStringPosition++; + ASSERT (CipherStringPosition == CipherString + CipherStringSize); + ); // // Sets the ciphers for use by the Tls object. // if (SSL_set_cipher_list (TlsConn->Ssl, CipherString) <= 0) { - return EFI_UNSUPPORTED; + Status = EFI_UNSUPPORTED; + goto FreeCipherString; } - return EFI_SUCCESS; + Status = EFI_SUCCESS; + +FreeCipherString: + FreePool (CipherString); + +FreeMappedCipher: + FreePool (MappedCipher); + + return Status; } /** diff --git a/CryptoPkg/Library/TlsLib/TlsLib.inf b/CryptoPkg/Library/TlsLib/TlsLib.inf index ae17a7d874..4dacb2fab0 100644 --- a/CryptoPkg/Library/TlsLib/TlsLib.inf +++ b/CryptoPkg/Library/TlsLib/TlsLib.inf @@ -40,11 +40,12 @@ [LibraryClasses] BaseCryptLib - BaseLib BaseMemoryLib DebugLib IntrinsicLib + MemoryAllocationLib OpensslLib + SafeIntLib [BuildOptions] #