mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-21 06:45:39 -06:00
Merge branch 'master' of https://github.com/ultimatepp/ultimatepp
This commit is contained in:
commit
65ae756caf
11 changed files with 684 additions and 8 deletions
97
Makefile
97
Makefile
|
|
@ -50123,6 +50123,97 @@ $(OutDir_Core_SSL)AES.o: $(UPPDIR1)Core/SSL/AES.cpp \
|
||||||
$(UPPDIR1)uppconfig.h
|
$(UPPDIR1)uppconfig.h
|
||||||
$(CXX) -c -x c++ $(CXXFLAGS) $(CINC) $(Macro_Core_SSL) $(UPPDIR1)Core/SSL/AES.cpp -o $(OutDir_Core_SSL)AES.o
|
$(CXX) -c -x c++ $(CXXFLAGS) $(CINC) $(Macro_Core_SSL) $(UPPDIR1)Core/SSL/AES.cpp -o $(OutDir_Core_SSL)AES.o
|
||||||
|
|
||||||
|
$(OutDir_Core_SSL)Random.o: $(UPPDIR1)Core/SSL/Random.cpp \
|
||||||
|
$(UPPDIR1)Core/Algo.h \
|
||||||
|
$(UPPDIR1)Core/App.h \
|
||||||
|
$(UPPDIR1)Core/AString.hpp \
|
||||||
|
$(UPPDIR1)Core/Atomic.h \
|
||||||
|
$(UPPDIR1)Core/BiCont.h \
|
||||||
|
$(UPPDIR1)Core/BinUndoRedo.h \
|
||||||
|
$(UPPDIR1)Core/Callback.h \
|
||||||
|
$(UPPDIR1)Core/CallbackN.i \
|
||||||
|
$(UPPDIR1)Core/CallbackNP.i \
|
||||||
|
$(UPPDIR1)Core/CallbackR.i \
|
||||||
|
$(UPPDIR1)Core/CharFilter.h \
|
||||||
|
$(UPPDIR1)Core/CharSet.h \
|
||||||
|
$(UPPDIR1)Core/CharSet.i \
|
||||||
|
$(UPPDIR1)Core/CoAlgo.h \
|
||||||
|
$(UPPDIR1)Core/Color.h \
|
||||||
|
$(UPPDIR1)Core/Complex.h \
|
||||||
|
$(UPPDIR1)Core/config.h \
|
||||||
|
$(UPPDIR1)Core/Convert.h \
|
||||||
|
$(UPPDIR1)Core/Convert.hpp \
|
||||||
|
$(UPPDIR1)Core/Core.h \
|
||||||
|
$(UPPDIR1)Core/CoSort.h \
|
||||||
|
$(UPPDIR1)Core/CoWork.h \
|
||||||
|
$(UPPDIR1)Core/Defs.h \
|
||||||
|
$(UPPDIR1)Core/Diag.h \
|
||||||
|
$(UPPDIR1)Core/FileMapping.h \
|
||||||
|
$(UPPDIR1)Core/FilterStream.h \
|
||||||
|
$(UPPDIR1)Core/FixedMap.h \
|
||||||
|
$(UPPDIR1)Core/Fn.h \
|
||||||
|
$(UPPDIR1)Core/Format.h \
|
||||||
|
$(UPPDIR1)Core/Function.h \
|
||||||
|
$(UPPDIR1)Core/Gtypes.h \
|
||||||
|
$(UPPDIR1)Core/Hash.h \
|
||||||
|
$(UPPDIR1)Core/Heap.h \
|
||||||
|
$(UPPDIR1)Core/HttpStatusCode.i \
|
||||||
|
$(UPPDIR1)Core/Huge.h \
|
||||||
|
$(UPPDIR1)Core/i18n.h \
|
||||||
|
$(UPPDIR1)Core/Index.h \
|
||||||
|
$(UPPDIR1)Core/Index.hpp \
|
||||||
|
$(UPPDIR1)Core/Inet.h \
|
||||||
|
$(UPPDIR1)Core/InMap.hpp \
|
||||||
|
$(UPPDIR1)Core/InVector.h \
|
||||||
|
$(UPPDIR1)Core/InVector.hpp \
|
||||||
|
$(UPPDIR1)Core/JSON.h \
|
||||||
|
$(UPPDIR1)Core/Lang.h \
|
||||||
|
$(UPPDIR1)Core/Lang_s.h \
|
||||||
|
$(UPPDIR1)Core/LocalProcess.h \
|
||||||
|
$(UPPDIR1)Core/Map.h \
|
||||||
|
$(UPPDIR1)Core/Map.hpp \
|
||||||
|
$(UPPDIR1)Core/Mem.h \
|
||||||
|
$(UPPDIR1)Core/Mt.h \
|
||||||
|
$(UPPDIR1)Core/Obsolete.h \
|
||||||
|
$(UPPDIR1)Core/Ops.h \
|
||||||
|
$(UPPDIR1)Core/Other.h \
|
||||||
|
$(UPPDIR1)Core/Other.hpp \
|
||||||
|
$(UPPDIR1)Core/Parser.h \
|
||||||
|
$(UPPDIR1)Core/Path.h \
|
||||||
|
$(UPPDIR1)Core/Profile.h \
|
||||||
|
$(UPPDIR1)Core/Ptr.h \
|
||||||
|
$(UPPDIR1)Core/Range.h \
|
||||||
|
$(UPPDIR1)Core/Sort.h \
|
||||||
|
$(UPPDIR1)Core/Sorted.h \
|
||||||
|
$(UPPDIR1)Core/SplitMerge.h \
|
||||||
|
$(UPPDIR1)Core/SSL/Buffer.hpp \
|
||||||
|
$(UPPDIR1)Core/SSL/Random.cpp \
|
||||||
|
$(UPPDIR1)Core/SSL/SSL.h \
|
||||||
|
$(UPPDIR1)Core/Stream.h \
|
||||||
|
$(UPPDIR1)Core/String.h \
|
||||||
|
$(UPPDIR1)Core/t_.h \
|
||||||
|
$(UPPDIR1)Core/TimeDate.h \
|
||||||
|
$(UPPDIR1)Core/Topic.h \
|
||||||
|
$(UPPDIR1)Core/Topt.h \
|
||||||
|
$(UPPDIR1)Core/Tuple.h \
|
||||||
|
$(UPPDIR1)Core/Utf.hpp \
|
||||||
|
$(UPPDIR1)Core/Util.h \
|
||||||
|
$(UPPDIR1)Core/Uuid.h \
|
||||||
|
$(UPPDIR1)Core/Value.h \
|
||||||
|
$(UPPDIR1)Core/Value.hpp \
|
||||||
|
$(UPPDIR1)Core/ValueCache.h \
|
||||||
|
$(UPPDIR1)Core/ValueUtil.h \
|
||||||
|
$(UPPDIR1)Core/ValueUtil.hpp \
|
||||||
|
$(UPPDIR1)Core/Vcont.h \
|
||||||
|
$(UPPDIR1)Core/Vcont.hpp \
|
||||||
|
$(UPPDIR1)Core/Win32Util.h \
|
||||||
|
$(UPPDIR1)Core/XML.h \
|
||||||
|
$(UPPDIR1)Core/Xmlize.h \
|
||||||
|
$(UPPDIR1)Core/Xmlize.hpp \
|
||||||
|
$(UPPDIR1)Core/z.h \
|
||||||
|
$(UPPDIR1)uppconfig.h
|
||||||
|
$(CXX) -c -x c++ $(CXXFLAGS) $(CINC) $(Macro_Core_SSL) $(UPPDIR1)Core/SSL/Random.cpp -o $(OutDir_Core_SSL)Random.o
|
||||||
|
|
||||||
$(OutDir_Core_SSL)SSL.o: $(UPPDIR1)Core/SSL/SSL.icpp \
|
$(OutDir_Core_SSL)SSL.o: $(UPPDIR1)Core/SSL/SSL.icpp \
|
||||||
$(UPPDIR1)Core/Algo.h \
|
$(UPPDIR1)Core/Algo.h \
|
||||||
$(UPPDIR1)Core/App.h \
|
$(UPPDIR1)Core/App.h \
|
||||||
|
|
@ -50219,13 +50310,15 @@ $(OutDir_Core_SSL)SSL.a: \
|
||||||
$(OutDir_Core_SSL)InitExit.o \
|
$(OutDir_Core_SSL)InitExit.o \
|
||||||
$(OutDir_Core_SSL)Socket.o \
|
$(OutDir_Core_SSL)Socket.o \
|
||||||
$(OutDir_Core_SSL)P7S.o \
|
$(OutDir_Core_SSL)P7S.o \
|
||||||
$(OutDir_Core_SSL)AES.o
|
$(OutDir_Core_SSL)AES.o \
|
||||||
|
$(OutDir_Core_SSL)Random.o
|
||||||
$(AR) $(OutDir_Core_SSL)SSL.a \
|
$(AR) $(OutDir_Core_SSL)SSL.a \
|
||||||
$(OutDir_Core_SSL)Util.o \
|
$(OutDir_Core_SSL)Util.o \
|
||||||
$(OutDir_Core_SSL)InitExit.o \
|
$(OutDir_Core_SSL)InitExit.o \
|
||||||
$(OutDir_Core_SSL)Socket.o \
|
$(OutDir_Core_SSL)Socket.o \
|
||||||
$(OutDir_Core_SSL)P7S.o \
|
$(OutDir_Core_SSL)P7S.o \
|
||||||
$(OutDir_Core_SSL)AES.o
|
$(OutDir_Core_SSL)AES.o \
|
||||||
|
$(OutDir_Core_SSL)Random.o
|
||||||
|
|
||||||
$(OutDir_plugin_md):
|
$(OutDir_plugin_md):
|
||||||
mkdir -p $(OutDir_plugin_md)
|
mkdir -p $(OutDir_plugin_md)
|
||||||
|
|
|
||||||
97
Makefile.in
97
Makefile.in
|
|
@ -50123,6 +50123,97 @@ $(OutDir_Core_SSL)AES.o: $(UPPDIR1)Core/SSL/AES.cpp \
|
||||||
$(UPPDIR1)uppconfig.h
|
$(UPPDIR1)uppconfig.h
|
||||||
$(CXX) -c -x c++ $(CXXFLAGS) $(CINC) $(Macro_Core_SSL) $(UPPDIR1)Core/SSL/AES.cpp -o $(OutDir_Core_SSL)AES.o
|
$(CXX) -c -x c++ $(CXXFLAGS) $(CINC) $(Macro_Core_SSL) $(UPPDIR1)Core/SSL/AES.cpp -o $(OutDir_Core_SSL)AES.o
|
||||||
|
|
||||||
|
$(OutDir_Core_SSL)Random.o: $(UPPDIR1)Core/SSL/Random.cpp \
|
||||||
|
$(UPPDIR1)Core/Algo.h \
|
||||||
|
$(UPPDIR1)Core/App.h \
|
||||||
|
$(UPPDIR1)Core/AString.hpp \
|
||||||
|
$(UPPDIR1)Core/Atomic.h \
|
||||||
|
$(UPPDIR1)Core/BiCont.h \
|
||||||
|
$(UPPDIR1)Core/BinUndoRedo.h \
|
||||||
|
$(UPPDIR1)Core/Callback.h \
|
||||||
|
$(UPPDIR1)Core/CallbackN.i \
|
||||||
|
$(UPPDIR1)Core/CallbackNP.i \
|
||||||
|
$(UPPDIR1)Core/CallbackR.i \
|
||||||
|
$(UPPDIR1)Core/CharFilter.h \
|
||||||
|
$(UPPDIR1)Core/CharSet.h \
|
||||||
|
$(UPPDIR1)Core/CharSet.i \
|
||||||
|
$(UPPDIR1)Core/CoAlgo.h \
|
||||||
|
$(UPPDIR1)Core/Color.h \
|
||||||
|
$(UPPDIR1)Core/Complex.h \
|
||||||
|
$(UPPDIR1)Core/config.h \
|
||||||
|
$(UPPDIR1)Core/Convert.h \
|
||||||
|
$(UPPDIR1)Core/Convert.hpp \
|
||||||
|
$(UPPDIR1)Core/Core.h \
|
||||||
|
$(UPPDIR1)Core/CoSort.h \
|
||||||
|
$(UPPDIR1)Core/CoWork.h \
|
||||||
|
$(UPPDIR1)Core/Defs.h \
|
||||||
|
$(UPPDIR1)Core/Diag.h \
|
||||||
|
$(UPPDIR1)Core/FileMapping.h \
|
||||||
|
$(UPPDIR1)Core/FilterStream.h \
|
||||||
|
$(UPPDIR1)Core/FixedMap.h \
|
||||||
|
$(UPPDIR1)Core/Fn.h \
|
||||||
|
$(UPPDIR1)Core/Format.h \
|
||||||
|
$(UPPDIR1)Core/Function.h \
|
||||||
|
$(UPPDIR1)Core/Gtypes.h \
|
||||||
|
$(UPPDIR1)Core/Hash.h \
|
||||||
|
$(UPPDIR1)Core/Heap.h \
|
||||||
|
$(UPPDIR1)Core/HttpStatusCode.i \
|
||||||
|
$(UPPDIR1)Core/Huge.h \
|
||||||
|
$(UPPDIR1)Core/i18n.h \
|
||||||
|
$(UPPDIR1)Core/Index.h \
|
||||||
|
$(UPPDIR1)Core/Index.hpp \
|
||||||
|
$(UPPDIR1)Core/Inet.h \
|
||||||
|
$(UPPDIR1)Core/InMap.hpp \
|
||||||
|
$(UPPDIR1)Core/InVector.h \
|
||||||
|
$(UPPDIR1)Core/InVector.hpp \
|
||||||
|
$(UPPDIR1)Core/JSON.h \
|
||||||
|
$(UPPDIR1)Core/Lang.h \
|
||||||
|
$(UPPDIR1)Core/Lang_s.h \
|
||||||
|
$(UPPDIR1)Core/LocalProcess.h \
|
||||||
|
$(UPPDIR1)Core/Map.h \
|
||||||
|
$(UPPDIR1)Core/Map.hpp \
|
||||||
|
$(UPPDIR1)Core/Mem.h \
|
||||||
|
$(UPPDIR1)Core/Mt.h \
|
||||||
|
$(UPPDIR1)Core/Obsolete.h \
|
||||||
|
$(UPPDIR1)Core/Ops.h \
|
||||||
|
$(UPPDIR1)Core/Other.h \
|
||||||
|
$(UPPDIR1)Core/Other.hpp \
|
||||||
|
$(UPPDIR1)Core/Parser.h \
|
||||||
|
$(UPPDIR1)Core/Path.h \
|
||||||
|
$(UPPDIR1)Core/Profile.h \
|
||||||
|
$(UPPDIR1)Core/Ptr.h \
|
||||||
|
$(UPPDIR1)Core/Range.h \
|
||||||
|
$(UPPDIR1)Core/Sort.h \
|
||||||
|
$(UPPDIR1)Core/Sorted.h \
|
||||||
|
$(UPPDIR1)Core/SplitMerge.h \
|
||||||
|
$(UPPDIR1)Core/SSL/Buffer.hpp \
|
||||||
|
$(UPPDIR1)Core/SSL/Random.cpp \
|
||||||
|
$(UPPDIR1)Core/SSL/SSL.h \
|
||||||
|
$(UPPDIR1)Core/Stream.h \
|
||||||
|
$(UPPDIR1)Core/String.h \
|
||||||
|
$(UPPDIR1)Core/t_.h \
|
||||||
|
$(UPPDIR1)Core/TimeDate.h \
|
||||||
|
$(UPPDIR1)Core/Topic.h \
|
||||||
|
$(UPPDIR1)Core/Topt.h \
|
||||||
|
$(UPPDIR1)Core/Tuple.h \
|
||||||
|
$(UPPDIR1)Core/Utf.hpp \
|
||||||
|
$(UPPDIR1)Core/Util.h \
|
||||||
|
$(UPPDIR1)Core/Uuid.h \
|
||||||
|
$(UPPDIR1)Core/Value.h \
|
||||||
|
$(UPPDIR1)Core/Value.hpp \
|
||||||
|
$(UPPDIR1)Core/ValueCache.h \
|
||||||
|
$(UPPDIR1)Core/ValueUtil.h \
|
||||||
|
$(UPPDIR1)Core/ValueUtil.hpp \
|
||||||
|
$(UPPDIR1)Core/Vcont.h \
|
||||||
|
$(UPPDIR1)Core/Vcont.hpp \
|
||||||
|
$(UPPDIR1)Core/Win32Util.h \
|
||||||
|
$(UPPDIR1)Core/XML.h \
|
||||||
|
$(UPPDIR1)Core/Xmlize.h \
|
||||||
|
$(UPPDIR1)Core/Xmlize.hpp \
|
||||||
|
$(UPPDIR1)Core/z.h \
|
||||||
|
$(UPPDIR1)uppconfig.h
|
||||||
|
$(CXX) -c -x c++ $(CXXFLAGS) $(CINC) $(Macro_Core_SSL) $(UPPDIR1)Core/SSL/Random.cpp -o $(OutDir_Core_SSL)Random.o
|
||||||
|
|
||||||
$(OutDir_Core_SSL)SSL.o: $(UPPDIR1)Core/SSL/SSL.icpp \
|
$(OutDir_Core_SSL)SSL.o: $(UPPDIR1)Core/SSL/SSL.icpp \
|
||||||
$(UPPDIR1)Core/Algo.h \
|
$(UPPDIR1)Core/Algo.h \
|
||||||
$(UPPDIR1)Core/App.h \
|
$(UPPDIR1)Core/App.h \
|
||||||
|
|
@ -50219,13 +50310,15 @@ $(OutDir_Core_SSL)SSL.a: \
|
||||||
$(OutDir_Core_SSL)InitExit.o \
|
$(OutDir_Core_SSL)InitExit.o \
|
||||||
$(OutDir_Core_SSL)Socket.o \
|
$(OutDir_Core_SSL)Socket.o \
|
||||||
$(OutDir_Core_SSL)P7S.o \
|
$(OutDir_Core_SSL)P7S.o \
|
||||||
$(OutDir_Core_SSL)AES.o
|
$(OutDir_Core_SSL)AES.o \
|
||||||
|
$(OutDir_Core_SSL)Random.o
|
||||||
$(AR) $(OutDir_Core_SSL)SSL.a \
|
$(AR) $(OutDir_Core_SSL)SSL.a \
|
||||||
$(OutDir_Core_SSL)Util.o \
|
$(OutDir_Core_SSL)Util.o \
|
||||||
$(OutDir_Core_SSL)InitExit.o \
|
$(OutDir_Core_SSL)InitExit.o \
|
||||||
$(OutDir_Core_SSL)Socket.o \
|
$(OutDir_Core_SSL)Socket.o \
|
||||||
$(OutDir_Core_SSL)P7S.o \
|
$(OutDir_Core_SSL)P7S.o \
|
||||||
$(OutDir_Core_SSL)AES.o
|
$(OutDir_Core_SSL)AES.o \
|
||||||
|
$(OutDir_Core_SSL)Random.o
|
||||||
|
|
||||||
$(OutDir_plugin_md):
|
$(OutDir_plugin_md):
|
||||||
mkdir -p $(OutDir_plugin_md)
|
mkdir -p $(OutDir_plugin_md)
|
||||||
|
|
|
||||||
233
autotest/SecureRandomGenerator/SecureRandomGenerator.cpp
Normal file
233
autotest/SecureRandomGenerator/SecureRandomGenerator.cpp
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
#include <Core/Core.h>
|
||||||
|
#include <Core/SSL/SSL.h>
|
||||||
|
|
||||||
|
using namespace Upp;
|
||||||
|
|
||||||
|
CONSOLE_APP_MAIN
|
||||||
|
{
|
||||||
|
StdLogSetup(LOG_COUT | LOG_FILE);
|
||||||
|
|
||||||
|
auto Test = [](const String& name, const Function<void()>& fn) {
|
||||||
|
String txt = "---" + name + ": ";
|
||||||
|
try {
|
||||||
|
fn();
|
||||||
|
txt << "PASSED";
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
txt << "FAILED";
|
||||||
|
}
|
||||||
|
LOG(txt);
|
||||||
|
};
|
||||||
|
|
||||||
|
Test("Basic functionality", [] {
|
||||||
|
ASSERT(SecureNonce(16).GetSize() == 16);
|
||||||
|
ASSERT(SecureNonce(64).GetSize() == 64);
|
||||||
|
ASSERT(SecureNonce(12).GetSize() == 12);
|
||||||
|
ASSERT(!SecureNonce(16).IsEmpty());
|
||||||
|
ASSERT(SecureNonce(1).GetSize() == 12); // Enforce minimum
|
||||||
|
ASSERT(SecureRandom(0).GetSize() == 1); // Enforce minimum
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Standard nonce helpers, length check", [] {
|
||||||
|
ASSERT(GetAESGCMNonce().GetSize() == 12);
|
||||||
|
ASSERT(GetChaChaPoly1305Nonce().GetSize() == 12);
|
||||||
|
ASSERT(GetTLSNonce().GetSize() == 12);
|
||||||
|
ASSERT(GetAESCCMNonce().GetSize() == 13);
|
||||||
|
ASSERT(GetJWTNonce().GetSize() == 16);
|
||||||
|
ASSERT(GetOAuthNonce().GetSize() == 16);
|
||||||
|
ASSERT(GetOCSPNonce().GetSize() == 20);
|
||||||
|
ASSERT(GetECDSANonce().GetSize() == 32);
|
||||||
|
ASSERT(GetDTLSCookie().GetSize() == 32);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("SecureRandom basic checks", [] {
|
||||||
|
auto buf = SecureRandom(32);
|
||||||
|
ASSERT(buf.GetSize() == 32);
|
||||||
|
ASSERT(!buf.IsEmpty());
|
||||||
|
|
||||||
|
// Verify it's not all zeros
|
||||||
|
bool has_nonzero = false;
|
||||||
|
for(size_t i = 0; i < buf.GetSize(); i++) {
|
||||||
|
if(buf[i] != 0) {
|
||||||
|
has_nonzero = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT(has_nonzero);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Uniqueness (single-threaded)", [] {
|
||||||
|
const int NONCE_COUNT = 1000;
|
||||||
|
Vector<String> nonces;
|
||||||
|
nonces.Reserve(NONCE_COUNT);
|
||||||
|
|
||||||
|
for(int i = 0; i < NONCE_COUNT; i++) {
|
||||||
|
auto buf = SecureNonce(12);
|
||||||
|
nonces.Add(String((const char*)~buf, buf.GetSize()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Sort(nonces);
|
||||||
|
for(int i = 1; i < nonces.GetCount(); i++)
|
||||||
|
ASSERT(nonces[i] != nonces[i - 1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Uniqueness (multi-threaded)", [] {
|
||||||
|
const int THREAD_COUNT = CPU_Cores();
|
||||||
|
const int NONCES_PER_THREAD = 100000;
|
||||||
|
Vector<String> all_nonces;
|
||||||
|
|
||||||
|
CoFor(THREAD_COUNT, [&all_nonces](int n) {
|
||||||
|
Vector<String> nonces;
|
||||||
|
nonces.Reserve(NONCES_PER_THREAD);
|
||||||
|
|
||||||
|
for(int i = 0; i < NONCES_PER_THREAD; i++) {
|
||||||
|
auto buf = SecureNonce(12);
|
||||||
|
nonces.Add(String((const char*)~buf, buf.GetSize()));
|
||||||
|
}
|
||||||
|
|
||||||
|
CoWork::FinLock();
|
||||||
|
all_nonces.AppendPick(pick(nonces));
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT(all_nonces.GetCount() == THREAD_COUNT * NONCES_PER_THREAD);
|
||||||
|
Sort(all_nonces);
|
||||||
|
|
||||||
|
for(int i = 1; i < all_nonces.GetCount(); i++)
|
||||||
|
ASSERT(all_nonces[i] != all_nonces[i - 1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Verify nonce internal structure (12-15 byte nonces)", [] {
|
||||||
|
auto nonce1 = SecureNonce(12);
|
||||||
|
auto nonce2 = SecureNonce(12);
|
||||||
|
|
||||||
|
// First 4 bytes (process ID) should be identical
|
||||||
|
ASSERT(memcmp(~nonce1, ~nonce2, 4) == 0);
|
||||||
|
|
||||||
|
// Next 8 bytes (counter) should differ
|
||||||
|
uint64 counter1 = Peek64(~nonce1 + 4);
|
||||||
|
uint64 counter2 = Peek64(~nonce2 + 4);
|
||||||
|
ASSERT(counter1 != counter2);
|
||||||
|
|
||||||
|
// Expect sequential or very close counters
|
||||||
|
// Allow for other threads potentially getting nonces in between
|
||||||
|
uint64 diff = (counter2 > counter1) ? (counter2 - counter1) : (counter1 - counter2);
|
||||||
|
ASSERT(diff <= 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Verify nonce internal structure (16+ byte nonces)", [] {
|
||||||
|
auto nonce1 = SecureNonce(16);
|
||||||
|
auto nonce2 = SecureNonce(16);
|
||||||
|
|
||||||
|
// First 8 bytes (process ID) should be identical
|
||||||
|
ASSERT(memcmp(~nonce1, ~nonce2, 8) == 0);
|
||||||
|
|
||||||
|
// Next 8 bytes (counter) should differ
|
||||||
|
uint64 counter1 = Peek64(~nonce1 + 8);
|
||||||
|
uint64 counter2 = Peek64(~nonce2 + 8);
|
||||||
|
ASSERT(counter1 != counter2);
|
||||||
|
|
||||||
|
uint64 diff = (counter2 > counter1) ? (counter2 - counter1) : (counter1 - counter2);
|
||||||
|
ASSERT(diff <= 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Verify nonce entropy (using chi-square method)", [] {
|
||||||
|
const int NONCE_SIZE = 32; // Total nonce size
|
||||||
|
const int RANDOM_OFFSET = 16; // Skip 8B PID + 8B counter
|
||||||
|
const int RANDOM_SIZE = NONCE_SIZE - RANDOM_OFFSET;
|
||||||
|
const int SAMPLE_COUNT = 1000;
|
||||||
|
const double CHI_SQUARE_THRESHOLD = 350.0; // 99% confidence
|
||||||
|
|
||||||
|
String random_bytes;
|
||||||
|
random_bytes.Reserve(SAMPLE_COUNT * RANDOM_SIZE);
|
||||||
|
|
||||||
|
// Generate samples
|
||||||
|
for(int i = 0; i < SAMPLE_COUNT; ++i) {
|
||||||
|
auto nonce = SecureNonce(NONCE_SIZE);
|
||||||
|
random_bytes.Cat((const char*)(~nonce + RANDOM_OFFSET), RANDOM_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frequency analysis
|
||||||
|
Vector<int> freq(256, 0);
|
||||||
|
const byte* data = (const byte*)(const char*)random_bytes;
|
||||||
|
for(int i = 0; i < random_bytes.GetLength(); ++i)
|
||||||
|
freq[data[i]]++;
|
||||||
|
|
||||||
|
// Chi-square test
|
||||||
|
double expected = random_bytes.GetLength() / 256.0;
|
||||||
|
double chi2 = 0.0;
|
||||||
|
for(int count : freq) {
|
||||||
|
double delta = count - expected;
|
||||||
|
chi2 += (delta * delta) / expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(chi2 < CHI_SQUARE_THRESHOLD);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Verify different nonce sizes use correct layouts", [] {
|
||||||
|
// 12-byte nonce: [4B PID | 8B counter]
|
||||||
|
auto nonce12 = SecureNonce(12);
|
||||||
|
ASSERT(nonce12.GetSize() == 12);
|
||||||
|
|
||||||
|
// 14-byte nonce: [4B PID | 8B counter | 2B random]
|
||||||
|
auto nonce14 = SecureNonce(14);
|
||||||
|
ASSERT(nonce14.GetSize() == 14);
|
||||||
|
|
||||||
|
// 16-byte nonce: [8B PID | 8B counter]
|
||||||
|
auto nonce16 = SecureNonce(16);
|
||||||
|
ASSERT(nonce16.GetSize() == 16);
|
||||||
|
|
||||||
|
// 32-byte nonce: [8B PID | 8B counter | 16B random]
|
||||||
|
auto nonce32 = SecureNonce(32);
|
||||||
|
ASSERT(nonce32.GetSize() == 32);
|
||||||
|
|
||||||
|
// Verify PID portions match where expected
|
||||||
|
// For <16 byte nonces, compare first 4 bytes
|
||||||
|
ASSERT(memcmp(~nonce12, ~nonce14, 4) == 0);
|
||||||
|
|
||||||
|
// For >=16 byte nonces, compare first 8 bytes
|
||||||
|
ASSERT(memcmp(~nonce16, ~nonce32, 8) == 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Concurrent nonce generation stress test", [] {
|
||||||
|
const int THREAD_COUNT = 16;
|
||||||
|
const int NONCES_PER_THREAD = 10000;
|
||||||
|
std::atomic<int> total_generated{0};
|
||||||
|
|
||||||
|
CoFor(THREAD_COUNT, [&total_generated](int n) {
|
||||||
|
for(int i = 0; i < NONCES_PER_THREAD; i++) {
|
||||||
|
auto nonce = SecureNonce(16);
|
||||||
|
ASSERT(nonce.GetSize() == 16);
|
||||||
|
ASSERT(!nonce.IsEmpty());
|
||||||
|
}
|
||||||
|
total_generated += NONCES_PER_THREAD;
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT(total_generated == THREAD_COUNT * NONCES_PER_THREAD);
|
||||||
|
});
|
||||||
|
|
||||||
|
Test("Helper functions return correct types", [] {
|
||||||
|
// Verify all helpers return SecureBuffer<byte>
|
||||||
|
auto gcm = GetAESGCMNonce();
|
||||||
|
auto chacha = GetChaChaPoly1305Nonce();
|
||||||
|
auto tls = GetTLSNonce();
|
||||||
|
auto ccm = GetAESCCMNonce();
|
||||||
|
auto jwt = GetJWTNonce();
|
||||||
|
auto oauth = GetOAuthNonce();
|
||||||
|
auto ocsp = GetOCSPNonce();
|
||||||
|
auto ecdsa = GetECDSANonce();
|
||||||
|
auto dtls = GetDTLSCookie();
|
||||||
|
|
||||||
|
// All should be non-empty
|
||||||
|
ASSERT(!gcm.IsEmpty());
|
||||||
|
ASSERT(!chacha.IsEmpty());
|
||||||
|
ASSERT(!tls.IsEmpty());
|
||||||
|
ASSERT(!ccm.IsEmpty());
|
||||||
|
ASSERT(!jwt.IsEmpty());
|
||||||
|
ASSERT(!oauth.IsEmpty());
|
||||||
|
ASSERT(!ocsp.IsEmpty());
|
||||||
|
ASSERT(!ecdsa.IsEmpty());
|
||||||
|
ASSERT(!dtls.IsEmpty());
|
||||||
|
});
|
||||||
|
|
||||||
|
LOG("=== All tests completed ===");
|
||||||
|
}
|
||||||
10
autotest/SecureRandomGenerator/SecureRandomGenerator.upp
Normal file
10
autotest/SecureRandomGenerator/SecureRandomGenerator.upp
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
uses
|
||||||
|
Core,
|
||||||
|
Core/SSL;
|
||||||
|
|
||||||
|
file
|
||||||
|
SecureRandomGenerator.cpp;
|
||||||
|
|
||||||
|
mainconfig
|
||||||
|
"" = "";
|
||||||
|
|
||||||
|
|
@ -6,6 +6,8 @@ namespace Upp {
|
||||||
|
|
||||||
#ifdef UPP_HEAP
|
#ifdef UPP_HEAP
|
||||||
|
|
||||||
|
#ifndef _DEBUG // temporary solution unless we find the source of all those harmless leaks
|
||||||
|
|
||||||
static int64 UPP_SSL_alloc = 0;
|
static int64 UPP_SSL_alloc = 0;
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
|
|
@ -81,6 +83,8 @@ static void *SslRealloc(void *ptr, size_t size)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void SocketInit();
|
void SocketInit();
|
||||||
|
|
||||||
INITIALIZER(SSL)
|
INITIALIZER(SSL)
|
||||||
|
|
|
||||||
146
uppsrc/Core/SSL/Random.cpp
Normal file
146
uppsrc/Core/SSL/Random.cpp
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
#include "SSL.h"
|
||||||
|
|
||||||
|
#define LLOG(x) // DLOG("SecureRandomGenerator: " << x)
|
||||||
|
|
||||||
|
namespace Upp {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::atomic<bool> sForked(false);
|
||||||
|
std::atomic<uint64> sId(0);
|
||||||
|
std::atomic<uint64> sCounter(0);
|
||||||
|
SpinLock sLock;
|
||||||
|
|
||||||
|
constexpr const int NONCE_MIN = 12;
|
||||||
|
constexpr const int NONCE_STRUCTURED_MIN = 16;
|
||||||
|
|
||||||
|
inline void FillRandom(void* ptr, int len)
|
||||||
|
{
|
||||||
|
if(len <= 0)
|
||||||
|
return;
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
|
if(RAND_status() != 1) {
|
||||||
|
RAND_poll();
|
||||||
|
if(RAND_status() != 1)
|
||||||
|
throw Exc("SecureRandom: RNG not seeded");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(RAND_bytes(reinterpret_cast<byte*>(ptr), len) != 1)
|
||||||
|
throw Exc("SecureRandom: RAND_bytes failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init()
|
||||||
|
{
|
||||||
|
static_assert(sizeof(uint64) == 8, "Secure random/nonce generator requires 64-bit integers");
|
||||||
|
|
||||||
|
SslInitThread();
|
||||||
|
|
||||||
|
ONCELOCK {
|
||||||
|
uint32 seed = 0;
|
||||||
|
FillRandom(&seed, sizeof(seed));
|
||||||
|
sCounter = (uint64) seed;
|
||||||
|
#ifdef PLATFORM_POSIX
|
||||||
|
pthread_atfork(nullptr, nullptr, [] {
|
||||||
|
sForked = true;
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
|
RAND_cleanup();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HandleFork()
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_POSIX
|
||||||
|
if(!sForked.load())
|
||||||
|
return;
|
||||||
|
// After fork(), child inherits RNG state. We must reseed once to avoid
|
||||||
|
// nonce/counter reuse. SpinLock ensures only one thread performs reseed
|
||||||
|
// while others wait until state becomes consistent.
|
||||||
|
SpinLock::Lock __(sLock);
|
||||||
|
if(sForked.load()) {
|
||||||
|
uint32 seed = 0;
|
||||||
|
FillRandom(&seed, sizeof(seed));
|
||||||
|
sCounter = (uint64) seed;
|
||||||
|
sId = 0;
|
||||||
|
sForked = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 GetNonceDomainId()
|
||||||
|
{
|
||||||
|
if(uint64 v = sId.load(); v)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
uint64 x = 0;
|
||||||
|
FillRandom(&x, sizeof(x));
|
||||||
|
if(!x) x = 1;
|
||||||
|
|
||||||
|
uint64 expected = 0;
|
||||||
|
if(sId.compare_exchange_strong(expected, x))
|
||||||
|
return x;
|
||||||
|
|
||||||
|
return sId.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 NextCounter()
|
||||||
|
{
|
||||||
|
// simple atomic increment is enough here
|
||||||
|
uint64 v = ++sCounter;
|
||||||
|
if(v == 0)
|
||||||
|
throw Exc("SecureRandom: counter overflow");
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SecureBuffer<byte> SecureRandom(int n)
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
HandleFork();
|
||||||
|
n = max(1, n);
|
||||||
|
SecureBuffer<byte> out(n);
|
||||||
|
FillRandom(~out, n);
|
||||||
|
return pick(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
SecureBuffer<byte> SecureNonce(int n)
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
HandleFork();
|
||||||
|
uint64 did = GetNonceDomainId();
|
||||||
|
uint64 cnt = NextCounter();
|
||||||
|
|
||||||
|
n = max(n, NONCE_MIN);
|
||||||
|
SecureBuffer<byte> out(n);
|
||||||
|
|
||||||
|
byte *p = ~out;
|
||||||
|
|
||||||
|
// 12-15 byte layout
|
||||||
|
// 4 bytes PID | 8 bytes counter | [random tail]
|
||||||
|
if(n < NONCE_STRUCTURED_MIN) {
|
||||||
|
Poke32(p, (dword) did);
|
||||||
|
p += sizeof(dword);
|
||||||
|
Poke64(p, (int64) cnt);
|
||||||
|
p += sizeof(int64);
|
||||||
|
if(int len = n - NONCE_MIN; len > 0)
|
||||||
|
FillRandom(p, len);
|
||||||
|
return pick(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 16-byte structured layout
|
||||||
|
// 8 bytes PID | 8 bytes counter | [random tail]
|
||||||
|
Poke64(p, (int64) did);
|
||||||
|
p += sizeof(int64);
|
||||||
|
Poke64(p, (int64) cnt);
|
||||||
|
p += sizeof(int64);
|
||||||
|
if(int len = n - NONCE_STRUCTURED_MIN; len > 0)
|
||||||
|
FillRandom(p, len);
|
||||||
|
return pick(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -185,4 +185,21 @@ bool AES256Decrypt(Stream& in, const String& password, Stream& out, Gate<int64,
|
||||||
|
|
||||||
// Secure buffer
|
// Secure buffer
|
||||||
#include "Buffer.hpp"
|
#include "Buffer.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Secure Random Generator
|
||||||
|
SecureBuffer<byte> SecureRandom(int n);
|
||||||
|
SecureBuffer<byte> SecureNonce(int n);
|
||||||
|
|
||||||
|
inline SecureBuffer<byte> GetAESGCMNonce() { return SecureNonce(12); } // 12 bytes, optimal for AES-GCM
|
||||||
|
inline SecureBuffer<byte> GetChaChaPoly1305Nonce() { return SecureNonce(12); } // 12 bytes, standard for ChaCha20-Poly1305
|
||||||
|
inline SecureBuffer<byte> GetTLSNonce() { return SecureNonce(12); } // 12 bytes, used in TLS 1.2/1.3
|
||||||
|
inline SecureBuffer<byte> GetAESCCMNonce() { return SecureNonce(13); } // 13 bytes, max size for AES-CCM
|
||||||
|
inline SecureBuffer<byte> GetJWTNonce() { return SecureNonce(16); } // 16 bytes, good for JWT
|
||||||
|
inline SecureBuffer<byte> GetOAuthNonce() { return SecureNonce(16); } // 16 bytes, common for OAuth
|
||||||
|
inline SecureBuffer<byte> GetOCSPNonce() { return SecureNonce(20); } // 20 bytes, OCSP nonce extension
|
||||||
|
inline SecureBuffer<byte> GetECDSANonce() { return SecureNonce(32); } // 32 bytes, for ECDSA signatures
|
||||||
|
inline SecureBuffer<byte> GetDTLSCookie() { return SecureNonce(32); } // 32 bytes, DTLS cookie
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ file
|
||||||
P7S.cpp,
|
P7S.cpp,
|
||||||
AES.cpp,
|
AES.cpp,
|
||||||
Buffer.hpp,
|
Buffer.hpp,
|
||||||
|
Random.cpp,
|
||||||
SSL.icpp,
|
SSL.icpp,
|
||||||
Docs readonly separator,
|
Docs readonly separator,
|
||||||
src.tpp,
|
src.tpp,
|
||||||
|
|
|
||||||
69
uppsrc/Core/SSL/src.tpp/Upp_SSL_Random_en-us.tpp
Normal file
69
uppsrc/Core/SSL/src.tpp/Upp_SSL_Random_en-us.tpp
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
topic "Secure random data and nonce generation";
|
||||||
|
[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class]
|
||||||
|
[l288;2 $$2,2#27521748481378242620020725143825:desc]
|
||||||
|
[0 $$3,0#96390100711032703541132217272105:end]
|
||||||
|
[H6;0 $$4,0#05600065144404261032431302351956:begin]
|
||||||
|
[i448;a25;kKO9;2 $$5,0#37138531426314131252341829483370:item]
|
||||||
|
[l288;a4;*@5;1 $$6,6#70004532496200323422659154056402:requirement]
|
||||||
|
[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param]
|
||||||
|
[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam]
|
||||||
|
[b42;2 $$9,9#13035079074754324216151401829390:normal]
|
||||||
|
[2 $$0,0#00000000000000000000000000000000:Default]
|
||||||
|
[{_}
|
||||||
|
[ {{10000@(113.42.0) [s0;%% [*@7;4 Secure Random and Nonce Generators]]}}&]
|
||||||
|
[s2; &]
|
||||||
|
[s2;%% These functions provides a cryptographically secure random
|
||||||
|
number and nonces compliant with NIST SP 800`-38D, tailored for
|
||||||
|
high`-security applications that demand guaranteed uniqueness
|
||||||
|
and strong collision resistance. The implementation ensures
|
||||||
|
process`-unique nonces and is fork`-safe on POSIX systems, automatically
|
||||||
|
reseeding after a fork to avoid duplication. &]
|
||||||
|
[s2;%% &]
|
||||||
|
[s2;%% The implementation is [/ thread`-safe], supporting concurrent
|
||||||
|
initialization and generation across threads without race conditions.
|
||||||
|
It enforces a minimum nonce size of 12 bytes, aligning with cryptographic
|
||||||
|
standards. &]
|
||||||
|
[s2;%% &]
|
||||||
|
[s2;%% The generator offers two distinct modes: one for producing
|
||||||
|
unique, non`-repeating nonces, and another for extracting purely
|
||||||
|
random data suitable for general`-purpose cryptographic use.&]
|
||||||
|
[s2; &]
|
||||||
|
[s3; &]
|
||||||
|
[ {{10000F(128)G(128)@1 [s0;%% [* Function List]]}}&]
|
||||||
|
[s3; &]
|
||||||
|
[s5;:Upp`:`:SecureRandom`(int`): SecureBuffer<[@(0.255.0) byte]> [* SecureRandom]([@(0.0.255) i
|
||||||
|
nt] [*@3 n])&]
|
||||||
|
[s2;%% Generates [%-*@3 n] cryptographically secure random bytes. Enforces
|
||||||
|
a minimum size of 1 bytes. Throws [^topic`:`/`/Core`/src`/Exc`_en`-us`#Exc`:`:class^ e
|
||||||
|
xception ]on failure.&]
|
||||||
|
[s3; &]
|
||||||
|
[s4; &]
|
||||||
|
[s5;:Upp`:`:SecureNonce`(int`): SecureBuffer<[@(0.255.0) byte]> [* SecureNonce]([@(0.0.255) i
|
||||||
|
nt] [*@3 n])&]
|
||||||
|
[s0;l288;%% Generates a secure nonce of [%-*@3 n] bytes. Enforces a
|
||||||
|
minimum size of 12 bytes. Throws [^topic`:`/`/Core`/src`/Exc`_en`-us`#Exc`:`:class^ e
|
||||||
|
xception ]on failure. The returned value is a structured binary
|
||||||
|
nonce produced from internal&]
|
||||||
|
[s2;%% domain, counter, and optional entropy components. All internal
|
||||||
|
multi`-byte fields are encoded using little`-endian layout.&]
|
||||||
|
[s3; &]
|
||||||
|
[ {{10000F(128)G(128)@1 [s0;%% [* Standard Nonce Helpers]]}}&]
|
||||||
|
[s3; &]
|
||||||
|
[s5;:Upp`:`:GetAESGCMNonce`(`): SecureBuffer<[@(0.255.0) byte]> [* GetAESGCMNonce]()&]
|
||||||
|
[s5;:Upp`:`:GetChaChaPoly1305Nonce`(`): SecureBuffer<[@(0.255.0) byte]>
|
||||||
|
[* GetChaChaPoly1305Nonce]()&]
|
||||||
|
[s5;:Upp`:`:GetTLSNonce`(`): SecureBuffer<[@(0.255.0) byte]> [* GetTLSNonce]()&]
|
||||||
|
[s5;:Upp`:`:GetAESCCMNonce`(`): SecureBuffer<[@(0.255.0) byte]> [* GetAESCCMNonce]()&]
|
||||||
|
[s5;:Upp`:`:GetJWTNonce`(`): SecureBuffer<[@(0.255.0) byte]> [* GetJWTNonce]()&]
|
||||||
|
[s5;:Upp`:`:GetOAuthNonce`(`): SecureBuffer<[@(0.255.0) byte]> [* GetOAuthNonce]()&]
|
||||||
|
[s5;:Upp`:`:GetOCSPNonce`(`): SecureBuffer<[@(0.255.0) byte]> [* GetOCSPNonce]()&]
|
||||||
|
[s5;:Upp`:`:GetECDSANonce`(`): SecureBuffer<[@(0.255.0) byte]> [* GetECDSANonce]()&]
|
||||||
|
[s5;:Upp`:`:GetDTLSCookie`(`): SecureBuffer<[@(0.255.0) byte]> [* GetDTLSCookie]()&]
|
||||||
|
[s2;%% These helper functions generate cryptographically secure nonces
|
||||||
|
of commonly required lengths for widely used protocols and standards
|
||||||
|
such as AES`-GCM, ChaCha20`-Poly1305, TLS, JWT, and ECDSA. Each
|
||||||
|
helper ensures the nonce meets the expected size and uniqueness
|
||||||
|
guarantees of its respective use case. Each helper throws [^topic`:`/`/Core`/src`/Exc`_en`-us`#Exc`:`:class^ e
|
||||||
|
xception ]on failure.&]
|
||||||
|
[s3; &]
|
||||||
|
[s0;%% ]]
|
||||||
|
|
@ -8,7 +8,7 @@ uses
|
||||||
|
|
||||||
library(WIN32) "advapi32 comdlg32 comctl32 imm32";
|
library(WIN32) "advapi32 comdlg32 comctl32 imm32";
|
||||||
|
|
||||||
library(PORTABLE_HYBRID) "brotlidec brotlicommon bz2 Xau";
|
library(PORTABLE_HYBRID) "brotlidec brotlicommon bz2 Xau uuid";
|
||||||
|
|
||||||
pkg_config(POSIX !OSX !VIRTUALGUI) "freetype2 x11 xinerama xrender xft xdmcp fontconfig xcb xext";
|
pkg_config(POSIX !OSX !VIRTUALGUI) "freetype2 x11 xinerama xrender xft xdmcp fontconfig xcb xext";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -580,11 +580,21 @@ bool GccBuilder::Link(const Vector<String>& linkfile, const String& linkoptions,
|
||||||
if(!HasFlag("SOLARIS") && !HasFlag("OSX") && !HasFlag("OBJC"))
|
if(!HasFlag("SOLARIS") && !HasFlag("OSX") && !HasFlag("OBJC"))
|
||||||
lnk << " -Wl,--start-group ";
|
lnk << " -Wl,--start-group ";
|
||||||
for(String s : pkg_config)
|
for(String s : pkg_config)
|
||||||
|
if(portable) {
|
||||||
|
DDUMP(s);
|
||||||
|
Vector<String> libs = Split(HostSys("pkg-config --libs " + s), CharFilterWhitespace);
|
||||||
|
DDUMP(libs);
|
||||||
|
libs.RemoveIf([&](int i) { return findarg(libs[i], "-ldl", "-lpthread", "-lrt", "-lm") >= 0; });
|
||||||
|
DDUMP(libs);
|
||||||
|
if(libs.GetCount())
|
||||||
|
lnk << ' ' << Join(libs, " ");
|
||||||
|
}
|
||||||
|
else
|
||||||
lnk << " `" << Host::CMDLINE_PREFIX << "pkg-config --libs " << s << "`";
|
lnk << " `" << Host::CMDLINE_PREFIX << "pkg-config --libs " << s << "`";
|
||||||
for(int pass = 0; pass < 2; pass++) {
|
for(int pass = 0; pass < 2; pass++) {
|
||||||
for(i = 0; i < lib.GetCount(); i++) {
|
for(i = 0; i < lib.GetCount(); i++) {
|
||||||
String ln = lib[i];
|
String ln = lib[i];
|
||||||
if(portable && (ln == "dl" || ln == "pthread" || ln == "rt"))
|
if(portable && (ln == "dl" || ln == "pthread" || ln == "rt" || ln == "m"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
String ext = ToLower(GetFileExt(ln));
|
String ext = ToLower(GetFileExt(ln));
|
||||||
|
|
@ -618,7 +628,7 @@ bool GccBuilder::Link(const Vector<String>& linkfile, const String& linkoptions,
|
||||||
lnk << " -Wl,--end-group";
|
lnk << " -Wl,--end-group";
|
||||||
}
|
}
|
||||||
if(portable)
|
if(portable)
|
||||||
lnk << " -Wl,-Bdynamic -lpthread -ldl -lrt";
|
lnk << " -Wl,-Bdynamic -lpthread -ldl -lrt -lm";
|
||||||
|
|
||||||
PutConsole("Linking...");
|
PutConsole("Linking...");
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue