Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libcotp for openSUSE:Factory checked in at 2023-12-13 18:35:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libcotp (Old) and /work/SRC/openSUSE:Factory/.libcotp.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libcotp" Wed Dec 13 18:35:46 2023 rev:12 rq:1132822 version:3.0.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libcotp/libcotp.changes 2023-11-28 22:21:03.105425808 +0100 +++ /work/SRC/openSUSE:Factory/.libcotp.new.25432/libcotp.changes 2023-12-13 18:35:55.600541767 +0100 @@ -1,0 +2,16 @@ +Wed Dec 13 08:53:29 UTC 2023 - Paolo Stivanin <i...@paolostivanin.com> + +- Update to 3.0.0: + * This release supersedes v2.1.0 and brings a new feature and + some small code improvements: + + Add support for OpenSSL (#52), by @mchalain + + Fix base32 encoding and decoding of bytes array (#54) + + make is_string_valid_b32 public + + improve code readability + +------------------------------------------------------------------- +Wed Dec 6 07:30:58 UTC 2023 - Paolo Stivanin <i...@paolostivanin.com> + +- Use correct library 'libcriterion-devel'. + +------------------------------------------------------------------- Old: ---- v2.1.0.tar.gz v2.1.0.tar.gz.asc New: ---- v3.0.0.tar.gz v3.0.0.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libcotp.spec ++++++ --- /var/tmp/diff_new_pack.1IMnsz/_old 2023-12-13 18:35:56.184563346 +0100 +++ /var/tmp/diff_new_pack.1IMnsz/_new 2023-12-13 18:35:56.188563494 +0100 @@ -16,9 +16,9 @@ # -%define libsoname %{name}2 +%define libsoname %{name}3 Name: libcotp -Version: 2.1.0 +Version: 3.0.0 Release: 0 Summary: C library for generating TOTP and HOTP License: Apache-2.0 @@ -31,7 +31,7 @@ BuildRequires: gcc %if 0%{?suse_version} >= 1600 %ifarch x86_64 -BuildRequires: libcriterion3-devel +BuildRequires: libcriterion-devel %endif %endif BuildRequires: libgcrypt-devel >= 1.8.0 ++++++ v2.1.0.tar.gz -> v3.0.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcotp-2.1.0/CMakeLists.txt new/libcotp-3.0.0/CMakeLists.txt --- old/libcotp-2.1.0/CMakeLists.txt 2023-11-28 14:26:25.000000000 +0100 +++ new/libcotp-3.0.0/CMakeLists.txt 2023-12-13 09:42:15.000000000 +0100 @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(cotp VERSION "2.1.0" LANGUAGES "C") +project(cotp VERSION "3.0.0" LANGUAGES "C") set(CMAKE_C_STANDARD 11) @@ -35,30 +35,28 @@ message("libcotp can't use ${HMAC_WRAPPER} for hmac") endif() -include_directories(${HMAC_INCLUDE_DIR} ${BASEENCODE_INCLUDE_DIRS}) - -link_directories(${HMAC_LIBRARY_DIRS} ${BASEENCODE_LIBRARY_DIRS}) +include_directories(${HMAC_INCLUDE_DIR}) +link_directories(${HMAC_LIBRARY_DIRS}) if (BUILD_TESTS) -add_subdirectory(tests) + add_subdirectory(tests) endif () set(COTP_HEADERS src/cotp.h - ) +) + set(SOURCE_FILES src/otp.c ${HMAC_SOURCE_FILES} src/utils/base32.c - ) +) # Set compiler flags for all targets add_compile_options(-Wall -Wextra -O3 -Wformat=2 -Wmissing-format-attribute -fstack-protector-strong -Wundef -Wmissing-format-attribute -fdiagnostics-color=always -Wstrict-prototypes -Wunreachable-code -Wchar-subscripts -Wwrite-strings -Wpointer-arith -Wbad-function-cast -Wcast-align -Werror=format-security -Werror=implicit-function-declaration -Wno-sign-compare -Wno-format-nonliteral -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3) -add_link_options(-Wl,--no-add-needed -Wl,--as-needed -Wl,-z,relro,-z,now) - add_library(cotp ${SOURCE_FILES}) target_link_libraries(cotp ${HMAC_LIBRARIES}) @@ -66,14 +64,13 @@ PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src PRIVATE - ${HMAC_INCLUDE_DIR} - ${BASEENCODE_INCLUDE_DIRS}) + ${HMAC_INCLUDE_DIR}) target_compile_options(cotp PRIVATE -Wall -Wextra -O3 -Wformat=2 -Wmissing-format-attribute -fstack-protector-strong -Wundef -Wmissing-format-attribute -fdiagnostics-color=always -Wstrict-prototypes -Wunreachable-code -Wchar-subscripts -Wwrite-strings -Wpointer-arith -Wbad-function-cast -Wcast-align -Werror=format-security -Werror=implicit-function-declaration -Wno-sign-compare -Wno-format-nonliteral -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3) target_link_directories(cotp PRIVATE - ${HMACLIBRARY_DIRS} ${BASEENCODE_LIBRARY_DIRS}) + ${HMACLIBRARY_DIRS}) set_target_properties(cotp PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcotp-2.1.0/README.md new/libcotp-3.0.0/README.md --- old/libcotp-2.1.0/README.md 2023-11-28 14:26:25.000000000 +0100 +++ new/libcotp-3.0.0/README.md 2023-12-13 09:42:15.000000000 +0100 @@ -96,10 +96,12 @@ uchar *base32_decode (const char *user_data, size_t data_len, cotp_error_t *err_code); + +bool is_string_valid_b32 (const char *user_data); ``` where: -- `user_data` is the data to be encoded/decoded +- `user_data` is the data to be encoded or decoded - `data_len` is the length of the data to be encoded/decoded - `err_code` is where the error is stored @@ -115,3 +117,6 @@ - `INVALID_USER_INPUT`, set if the given input is not valid Both functions return and empty string if the input is an empty string. In such a case, `err` is set to `EMPTY_STRING`. + +`is_string_valid_b32` returns `true` if `user_data` is a valid base32 encoded string, `false` otherwise. Please note that `user_data` can contain spaces, since +the fucntion will also take care of trimming those. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcotp-2.1.0/SECURITY.md new/libcotp-3.0.0/SECURITY.md --- old/libcotp-2.1.0/SECURITY.md 2023-11-28 14:26:25.000000000 +0100 +++ new/libcotp-3.0.0/SECURITY.md 2023-12-13 09:42:15.000000000 +0100 @@ -6,8 +6,8 @@ | Version | Supported | EOL | |---------| ------------------ |-------------| -| 2.1.x | :heavy_check_mark: | - | -| 2.0.x | :heavy_check_mark: | 31-Dec-2023 | +| 3.0.x | :white_check_mark: | - | +| 2.0.x | :white_check_mark: | 31-Dec-2023 | | 1.2.x | :x: | 30-Jun-2023 | | 1.1.x | :x: | 31-Dec-2021 | | 1.0.x | :x: | 31-Dec-2021 | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcotp-2.1.0/src/cotp.h new/libcotp-3.0.0/src/cotp.h --- old/libcotp-2.1.0/src/cotp.h 2023-11-28 14:26:25.000000000 +0100 +++ new/libcotp-3.0.0/src/cotp.h 2023-12-13 09:42:15.000000000 +0100 @@ -1,5 +1,6 @@ #pragma once #include <stdint.h> +#include <stdbool.h> #define SHA1 0 #define SHA256 1 @@ -30,6 +31,8 @@ extern "C" { #endif +extern const uint8_t b32_alphabet[]; + char *base32_encode (const uchar *user_data, size_t data_len, cotp_error_t *err_code); @@ -38,6 +41,8 @@ size_t data_len, cotp_error_t *err_code); +bool is_string_valid_b32 (const char *user_data); + char *get_hotp (const char *base32_encoded_secret, long counter, int digits, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcotp-2.1.0/src/utils/base32.c new/libcotp-3.0.0/src/utils/base32.c --- old/libcotp-2.1.0/src/utils/base32.c 2023-11-28 14:26:25.000000000 +0100 +++ new/libcotp-3.0.0/src/utils/base32.c 2023-12-13 09:42:15.000000000 +0100 @@ -1,10 +1,7 @@ -#include <stdint.h> #include <stdlib.h> #include <string.h> #include "../cotp.h" -#define FALSE 0 -#define TRUE !FALSE #define BITS_PER_BYTE 8 #define BITS_PER_B32_BLOCK 5 @@ -14,18 +11,19 @@ // if 64 MB of data is encoded than it should be also possible to decode it. That's why a bigger input is allowed for decoding #define MAX_DECODE_BASE32_INPUT_LEN ((MAX_ENCODE_INPUT_LEN * 8 + 4) / 5) -static int is_valid_b32_input (const char *user_data); +const uint8_t b32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; -static int get_char_index (uint8_t c); +static int get_char_index (uint8_t c); -static cotp_error_t check_input (const uint8_t *user_data, - size_t data_len, - int32_t max_len); +static bool valid_b32_str (const char *str); -static int strip_char (char *str, - char strip); +static bool has_space (const char *str); -static const uint8_t b32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; +static cotp_error_t check_input (const uint8_t *user_data, + size_t data_len, + int32_t max_len); + +static int strip_char (char *str); // The encoding process represents 40-bit groups of input bits as output strings of 8 encoded characters. The input data must be null terminated. @@ -46,13 +44,13 @@ size_t user_data_chars = 0, total_bits = 0; int num_of_equals = 0; - int null_terminated = FALSE; + int null_terminated = false; if (strlen ((char *)user_data) == data_len - 1) { // the user might give the input with the null byte, we need to check for that - null_terminated = TRUE; + null_terminated = true; } for (int i = 0; i < data_len; i++) { - if (null_terminated == TRUE && user_data[i] == '\0' && i == data_len-1) { + if (null_terminated == true && user_data[i] == '\0' && i == data_len-1) { break; } total_bits += 8; @@ -72,30 +70,16 @@ return NULL; } - for (int i = 0, j = 0; i < user_data_chars;) { - uint64_t first_octet = user_data[i++]; - uint64_t second_octet = i < user_data_chars ? user_data[i++] : 0; - uint64_t third_octet = i < user_data_chars ? user_data[i++] : 0; - uint64_t fourth_octet = i < user_data_chars ? user_data[i++] : 0; - uint64_t fifth_octet = i < user_data_chars ? user_data[i++] : 0; - uint64_t quintuple = - ((first_octet >> 3) << 35) + - ((((first_octet & 0x7) << 2) | (second_octet >> 6)) << 30) + - (((second_octet & 0x3F) >> 1) << 25) + - ((((second_octet & 0x01) << 4) | (third_octet >> 4)) << 20) + - ((((third_octet & 0xF) << 1) | (fourth_octet >> 7)) << 15) + - (((fourth_octet & 0x7F) >> 2) << 10) + - ((((fourth_octet & 0x3) << 3) | (fifth_octet >> 5)) << 5) + - (fifth_octet & 0x1F); - - encoded_data[j++] = (char)b32_alphabet[(quintuple >> 35) & 0x1F]; - encoded_data[j++] = (char)b32_alphabet[(quintuple >> 30) & 0x1F]; - encoded_data[j++] = (char)b32_alphabet[(quintuple >> 25) & 0x1F]; - encoded_data[j++] = (char)b32_alphabet[(quintuple >> 20) & 0x1F]; - encoded_data[j++] = (char)b32_alphabet[(quintuple >> 15) & 0x1F]; - encoded_data[j++] = (char)b32_alphabet[(quintuple >> 10) & 0x1F]; - encoded_data[j++] = (char)b32_alphabet[(quintuple >> 5) & 0x1F]; - encoded_data[j++] = (char)b32_alphabet[(quintuple >> 0) & 0x1F]; + for (int i = 0, j = 0; i < user_data_chars; i += 5) { + uint64_t quintuple = 0; + + for (int k = 0; k < 5; k++) { + quintuple = (quintuple << 8) | (i + k < user_data_chars ? user_data[i + k] : 0); + } + + for (int shift = 35; shift >= 0; shift -= 5) { + encoded_data[j++] = (char)b32_alphabet[(quintuple >> shift) & 0x1F]; + } } for (int i = 0; i < num_of_equals; i++) { @@ -129,9 +113,9 @@ *err_code = MEMORY_ALLOCATION_ERROR; return NULL; } - data_len -= strip_char(user_data, ' '); + data_len -= strip_char (user_data); - if (!is_valid_b32_input(user_data)) { + if (!is_string_valid_b32 (user_data)) { free (user_data); *err_code = INVALID_B32_INPUT; return NULL; @@ -159,11 +143,11 @@ int char_index = get_char_index ((uint8_t)user_data[i]); if (bits_left > BITS_PER_B32_BLOCK) { mask = (uint8_t)char_index << (bits_left - BITS_PER_B32_BLOCK); - current_byte = (uint8_t) (current_byte | mask); + current_byte |= mask; bits_left -= BITS_PER_B32_BLOCK; } else { mask = (uint8_t)char_index >> (BITS_PER_B32_BLOCK - bits_left); - current_byte = (uint8_t) (current_byte | mask); + current_byte |= mask; decoded_data[j++] = current_byte; current_byte = (uint8_t) (char_index << (BITS_PER_BYTE - BITS_PER_B32_BLOCK + bits_left)); bits_left += BITS_PER_BYTE - BITS_PER_B32_BLOCK; @@ -179,31 +163,69 @@ } -static int -is_valid_b32_input (const char *user_data) +bool +is_string_valid_b32 (const char *user_data) { - // Create a lookup table for ASCII characters - uint8_t table[128]; - memset (table, 0, sizeof (table)); - for (size_t i = 0; i < sizeof (b32_alphabet); i++) { - table[b32_alphabet[i]] = 1; + if (user_data == NULL) { + return false; + } + + if (has_space (user_data)) { + char *trimmed = strdup (user_data); + if (trimmed == NULL) { + return false; + } + strip_char (trimmed); + bool valid = valid_b32_str (trimmed); + free(trimmed); + return valid; + } + + return valid_b32_str (user_data); +} + + +static bool +valid_b32_str (const char *str) +{ + if (str == NULL) { + return false; + } + + uint8_t table[128] = {0}; + for (const uint8_t *p = b32_alphabet; *p; p++) { + table[*p] = 1; } table['='] = 1; - const char *p; - for (p = user_data; *p; p++) { - if (!table[*(uint8_t *)p]) { - return 0; + while (*str) { + if (!table[(uint8_t)*str]) { + return false; + } + str++; + } + + return true; +} + + +static bool +has_space (const char *str) +{ + while (*str) { + if (*str == ' ') { + return true; } + str++; } - return 1; + return false; } static int get_char_index (uint8_t c) { - for (int i = 0; i < sizeof (b32_alphabet); i++) { + for (int i = 0; i < sizeof(b32_alphabet); i++) { if (b32_alphabet[i] == c) { return i; } @@ -213,17 +235,13 @@ static int -strip_char (char *str, - char strip) +strip_char (char *str) { - int found = 0; - - // Create a lookup table for ASCII characters - uint8_t table[128]; - memset (table, 0, sizeof (table)); - table[(int)strip] = 1; + const char strip = ' '; + uint8_t table[128] = {0}; + table[(uint8_t)strip] = 1; - // Iterate through the string using pointers + int found = 0; char *p, *q; for (q = p = str; *p; p++) { if (!table[*(uint8_t *)p]) {