summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinhard Tartler <siretart@tauware.de>2018-03-03 11:30:28 -0500
committerReinhard Tartler <siretart@tauware.de>2018-03-03 11:30:28 -0500
commit3d8a2866c3b8fc98ecba8b54af3e29860ff705af (patch)
tree2595330c322976a64a5de9810136c0afe4abdff9
parentac99c8589f0e74893cea3822c1511b322530dfc7 (diff)
parent5c8edd41853a7a08f2eab8365f0f48a12035a6b6 (diff)
Merge branch 'upstream' into HEAD
-rwxr-xr-xinfrastructure/travis-build.sh19
-rw-r--r--lib/common/Guards.h5
-rw-r--r--lib/crypto/CipherBlowfish.cpp2
-rw-r--r--lib/crypto/CipherBlowfish.h2
-rw-r--r--lib/crypto/CipherContext.cpp41
-rw-r--r--lib/crypto/CipherContext.h2
-rw-r--r--test/backupstore/testbackupstore.cpp152
-rw-r--r--test/backupstore/testfiles/encrypted.dirbin0 -> 160 bytes
-rw-r--r--test/crypto/testcrypto.cpp74
-rw-r--r--test/crypto/testfiles/bbackupd.keysbin0 -> 1024 bytes
-rwxr-xr-xtest/crypto/testfiles/bfdlink.h555
-rw-r--r--test/crypto/testfiles/bfdlink.h.encbin0 -> 22592 bytes
12 files changed, 757 insertions, 95 deletions
diff --git a/infrastructure/travis-build.sh b/infrastructure/travis-build.sh
index 74b58a3d..9ee3569e 100755
--- a/infrastructure/travis-build.sh
+++ b/infrastructure/travis-build.sh
@@ -4,11 +4,15 @@ set -e
set -x
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
- brew update
+ # No need to "brew update" first: https://docs.travis-ci.com/user/reference/osx/#Homebrew
+ # brew update
+
# Travis appears to have Boost and OpenSSL installed already:
# brew install boost ccache openssl
- ls /usr/local /usr/local/opt /usr/local/opt/openssl
- brew install ccache
+ ls /usr/local /usr/local/opt /usr/local/opt/openssl /usr/local/opt/openssl@1.1
+
+ # Use OSX builds to test OpenSSL 1.1 compatibility as well:
+ brew install ccache openssl@1.1
fi
ccache -s
@@ -20,7 +24,9 @@ if [ "$BUILD" = 'cmake' ]; then
fi
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
- EXTRA_ARGS="-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DBOOST_ROOT=/usr/local/opt/boost"
+ EXTRA_ARGS="
+ -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1
+ -DBOOST_ROOT=/usr/local/opt/boost"
fi
cd `dirname $0`
@@ -33,7 +39,10 @@ if [ "$BUILD" = 'cmake' ]; then
[ "$TEST" = "n" ] || ctest -C $TEST_TARGET -V
else
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
- EXTRA_ARGS="--with-ssl-lib=/usr/local/opt/openssl/lib --with-ssl-headers=/usr/local/opt/openssl/include --with-boost=/usr/local/opt/boost"
+ EXTRA_ARGS="
+ --with-ssl-lib=/usr/local/opt/openssl@1.1/lib
+ --with-ssl-headers=/usr/local/opt/openssl@1.1/include
+ --with-boost=/usr/local/opt/boost"
fi
cd `dirname $0`/..
diff --git a/lib/common/Guards.h b/lib/common/Guards.h
index 46b6d2bd..3637b261 100644
--- a/lib/common/Guards.h
+++ b/lib/common/Guards.h
@@ -110,6 +110,11 @@ public:
return (type)mpBlock;
}
+ int GetSize() const
+ {
+ return mBlockSize;
+ }
+
void Resize(int NewSize)
{
void *ptrn = ::realloc(mpBlock, NewSize);
diff --git a/lib/crypto/CipherBlowfish.cpp b/lib/crypto/CipherBlowfish.cpp
index 4c75b1de..e16cc6ed 100644
--- a/lib/crypto/CipherBlowfish.cpp
+++ b/lib/crypto/CipherBlowfish.cpp
@@ -206,7 +206,7 @@ void CipherBlowfish::SetupParameters(EVP_CIPHER_CTX *pCipherContext) const
}
// Set key
#ifndef HAVE_OLD_SSL
- if(EVP_CipherInit_ex(pCipherContext, GetCipher(), NULL, (unsigned char*)mpKey, (unsigned char*)mpInitialisationVector, -1) != 1)
+ if(EVP_CipherInit_ex(pCipherContext, NULL, NULL, (unsigned char*)mpKey, (unsigned char*)mpInitialisationVector, -1) != 1)
#else
if(EVP_CipherInit(pCipherContext, NULL, (unsigned char*)mKey.c_str(), (unsigned char*)mInitialisationVector, -1) != 1)
#endif
diff --git a/lib/crypto/CipherBlowfish.h b/lib/crypto/CipherBlowfish.h
index 152a265c..1894e2ac 100644
--- a/lib/crypto/CipherBlowfish.h
+++ b/lib/crypto/CipherBlowfish.h
@@ -41,7 +41,7 @@ public:
virtual std::string GetCipherName() const
{
std::ostringstream out;
- out << "AES";
+ out << "Blowfish";
out << mKeyLength;
return out.str();
}
diff --git a/lib/crypto/CipherContext.cpp b/lib/crypto/CipherContext.cpp
index 3de88c64..3f9a08b7 100644
--- a/lib/crypto/CipherContext.cpp
+++ b/lib/crypto/CipherContext.cpp
@@ -125,7 +125,6 @@ void CipherContext::Init(CipherContext::CipherFunction Function, const CipherDes
"Failed to initialise " << rDescription.GetFullName()
<< ": " << LogError("initialising cipher"));
}
- UsePadding(mPaddingOn);
try
{
@@ -179,7 +178,6 @@ void CipherContext::Reset()
}
#endif
mWithinTransform = false;
- mIV.clear();
}
@@ -203,8 +201,7 @@ void CipherContext::Begin()
THROW_EXCEPTION(CipherException, AlreadyInTransform);
}
- if(EVP_CipherInit_ex(BOX_OPENSSL_CTX(ctx), NULL, NULL, NULL,
- (const unsigned char *)(mIV.size() > 0 ? mIV.c_str() : NULL),
+ if(EVP_CipherInit_ex(BOX_OPENSSL_CTX(ctx), NULL, NULL, NULL, NULL,
-1) != 1)
{
THROW_EXCEPTION_MESSAGE(CipherException, EVPInitFailure,
@@ -391,14 +388,12 @@ void CipherContext::OldOpenSSLFinal(unsigned char *Buffer, int &rOutLengthOut)
}
}
// Reinitialise the cipher for the next time around
- if(EVP_CipherInit_ex(&ctx, mpDescription->GetCipher(), NULL, NULL,
- (const unsigned char *)(mIV.size() > 0 ? mIV.c_str() : NULL),
+ if(EVP_CipherInit_ex(&ctx, mpDescription->GetCipher(), NULL, NULL, NULL,
(mFunction == Encrypt) ? 1 : 0) != 1)
{
THROW_EXCEPTION(CipherException, EVPInitFailure)
}
mpDescription->SetupParameters(&ctx);
- UsePadding(mPaddingOn);
// Update length for caller
rOutLengthOut = outLength;
@@ -458,6 +453,18 @@ int CipherContext::MaxOutSizeForInBufferSize(int InLength)
// --------------------------------------------------------------------------
int CipherContext::TransformBlock(void *pOutBuffer, int OutLength, const void *pInBuffer, int InLength)
{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ // Warn if in a transformation
+ if(mWithinTransform)
+ {
+ BOX_WARNING("CipherContext::TransformBlock called when "
+ "context flagged as within a transform");
+ }
+
// Check output buffer size
if(OutLength < (InLength + EVP_CIPHER_CTX_block_size(BOX_OPENSSL_CTX(ctx))))
{
@@ -472,7 +479,11 @@ int CipherContext::TransformBlock(void *pOutBuffer, int OutLength, const void *p
}
}
- Begin();
+ // Initialise the cipher context again
+ if(EVP_CipherInit_ex(BOX_OPENSSL_CTX(ctx), NULL, NULL, NULL, NULL, -1) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
// Do the entire block
int output_space_used = OutLength;
@@ -545,11 +556,8 @@ void CipherContext::SetIV(const void *pIV)
"flagged as within a transform");
}
- mIV = std::string((const char *)pIV, GetIVLength());
-
// Set IV
- if(EVP_CipherInit_ex(BOX_OPENSSL_CTX(ctx), NULL, NULL, NULL,
- (const unsigned char *)mIV.c_str(), -1) != 1)
+ if(EVP_CipherInit_ex(BOX_OPENSSL_CTX(ctx), NULL, NULL, NULL, (unsigned char *)pIV, -1) != 1)
{
THROW_EXCEPTION_MESSAGE(CipherException, EVPInitFailure,
"Failed to set IV for " << mCipherName << ": " << LogError(GetFunction()));
@@ -589,20 +597,19 @@ const void *CipherContext::SetRandomIV(int &rLengthOut)
}
// Get length of IV
- uint8_t generated_iv[CIPHERCONTEXT_MAX_GENERATED_IV_LENGTH];
unsigned int ivLen = EVP_CIPHER_CTX_iv_length(BOX_OPENSSL_CTX(ctx));
- if(ivLen > sizeof(generated_iv))
+ if(ivLen > sizeof(mGeneratedIV))
{
THROW_EXCEPTION(CipherException, IVSizeImplementationLimitExceeded)
}
// Generate some random data
- Random::Generate(generated_iv, ivLen);
- SetIV(generated_iv);
+ Random::Generate(mGeneratedIV, ivLen);
+ SetIV(mGeneratedIV);
// Return the IV and it's length
rLengthOut = ivLen;
- return mIV.c_str();
+ return mGeneratedIV;
}
diff --git a/lib/crypto/CipherContext.h b/lib/crypto/CipherContext.h
index b6e97b4e..a0e45266 100644
--- a/lib/crypto/CipherContext.h
+++ b/lib/crypto/CipherContext.h
@@ -94,10 +94,10 @@ private:
bool mInitialised;
bool mWithinTransform;
bool mPaddingOn;
+ uint8_t mGeneratedIV[CIPHERCONTEXT_MAX_GENERATED_IV_LENGTH];
CipherFunction mFunction;
std::string mCipherName;
const CipherDescription *mpDescription;
- std::string mIV;
};
diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp
index 6441d66c..891d1461 100644
--- a/test/backupstore/testbackupstore.cpp
+++ b/test/backupstore/testbackupstore.cpp
@@ -274,81 +274,95 @@ bool test_filename_encoding()
SETUP_TEST_BACKUPSTORE();
// test some basics -- encoding and decoding filenames
+
+ // Make some filenames in various ways
+ BackupStoreFilenameClear fn1;
+ fn1.SetClearFilename(std::string("filenameXYZ"));
+ BackupStoreFilenameClear fn2(std::string("filenameXYZ"));
+ BackupStoreFilenameClear fn3(fn1);
+ TEST_THAT(fn1 == fn2);
+ TEST_THAT(fn1 == fn3);
+
+ // Check that it's been encrypted
+ std::string name(fn2.GetEncodedFilename());
+ TEST_THAT(name.find("name") == name.npos);
+
+ // Bung it in a stream, get it out in a Clear filename
{
- // Make some filenames in various ways
- BackupStoreFilenameClear fn1;
- fn1.SetClearFilename(std::string("filenameXYZ"));
- BackupStoreFilenameClear fn2(std::string("filenameXYZ"));
- BackupStoreFilenameClear fn3(fn1);
- TEST_THAT(fn1 == fn2);
- TEST_THAT(fn1 == fn3);
+ CollectInBufferStream stream;
+ fn1.WriteToStream(stream);
+ stream.SetForReading();
+ BackupStoreFilenameClear fn4;
+ fn4.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ TEST_THAT(fn4.GetClearFilename() == "filenameXYZ");
+ TEST_THAT(fn4 == fn1);
+ }
- // Check that it's been encrypted
- std::string name(fn2.GetEncodedFilename());
- TEST_THAT(name.find("name") == name.npos);
+ // Bung it in a stream, get it out in a server non-Clear filename (two of them into the same var)
+ {
+ BackupStoreFilenameClear fno("pinglet dksfnsf jksjdf ");
+ CollectInBufferStream stream;
+ fn1.WriteToStream(stream);
+ fno.WriteToStream(stream);
+ stream.SetForReading();
+ BackupStoreFilename fn5;
+ fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ TEST_THAT(fn5 == fn1);
+ fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ TEST_THAT(fn5 == fno);
+ }
- // Bung it in a stream, get it out in a Clear filename
- {
- CollectInBufferStream stream;
- fn1.WriteToStream(stream);
- stream.SetForReading();
- BackupStoreFilenameClear fn4;
- fn4.ReadFromStream(stream, IOStream::TimeOutInfinite);
- TEST_THAT(fn4.GetClearFilename() == "filenameXYZ");
- TEST_THAT(fn4 == fn1);
- }
+ // Same again with clear strings
+ {
+ BackupStoreFilenameClear fno("pinglet dksfnsf jksjdf ");
+ CollectInBufferStream stream;
+ fn1.WriteToStream(stream);
+ fno.WriteToStream(stream);
+ stream.SetForReading();
+ BackupStoreFilenameClear fn5;
+ fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ TEST_THAT(fn5.GetClearFilename() == "filenameXYZ");
+ fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ TEST_THAT(fn5.GetClearFilename() == "pinglet dksfnsf jksjdf ");
+ }
- // Bung it in a stream, get it out in a server non-Clear filename (two of them into the same var)
- {
- BackupStoreFilenameClear fno("pinglet dksfnsf jksjdf ");
- CollectInBufferStream stream;
- fn1.WriteToStream(stream);
- fno.WriteToStream(stream);
- stream.SetForReading();
- BackupStoreFilename fn5;
- fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
- TEST_THAT(fn5 == fn1);
- fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
- TEST_THAT(fn5 == fno);
- }
+ // Test a very big filename
+ {
+ const char *fnr = "01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789";
+ BackupStoreFilenameClear fnLong(fnr);
+ CollectInBufferStream stream;
+ fnLong.WriteToStream(stream);
+ stream.SetForReading();
+ BackupStoreFilenameClear fn9;
+ fn9.ReadFromStream(stream, IOStream::TimeOutInfinite);
+ TEST_THAT(fn9.GetClearFilename() == fnr);
+ TEST_THAT(fn9 == fnLong);
+ }
- // Same again with clear strings
- {
- BackupStoreFilenameClear fno("pinglet dksfnsf jksjdf ");
- CollectInBufferStream stream;
- fn1.WriteToStream(stream);
- fno.WriteToStream(stream);
- stream.SetForReading();
- BackupStoreFilenameClear fn5;
- fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
- TEST_THAT(fn5.GetClearFilename() == "filenameXYZ");
- fn5.ReadFromStream(stream, IOStream::TimeOutInfinite);
- TEST_THAT(fn5.GetClearFilename() == "pinglet dksfnsf jksjdf ");
- }
-
- // Test a very big filename
- {
- const char *fnr = "01234567890123456789012345678901234567890123456789"
- "01234567890123456789012345678901234567890123456789"
- "01234567890123456789012345678901234567890123456789"
- "01234567890123456789012345678901234567890123456789"
- "01234567890123456789012345678901234567890123456789"
- "01234567890123456789012345678901234567890123456789"
- "01234567890123456789012345678901234567890123456789"
- "01234567890123456789012345678901234567890123456789";
- BackupStoreFilenameClear fnLong(fnr);
- CollectInBufferStream stream;
- fnLong.WriteToStream(stream);
- stream.SetForReading();
- BackupStoreFilenameClear fn9;
- fn9.ReadFromStream(stream, IOStream::TimeOutInfinite);
- TEST_THAT(fn9.GetClearFilename() == fnr);
- TEST_THAT(fn9 == fnLong);
- }
+ // Test a filename which went wrong once
+ {
+ BackupStoreFilenameClear dodgy("content-negotiation.html");
+ }
- // Test a filename which went wrong once
- {
- BackupStoreFilenameClear dodgy("content-negotiation.html");
+ // Test that we can decrypt filenames in a previously-encrypted directory, to detect
+ // regressions of the encryption setup:
+ {
+ FileStream dir_file("testfiles/encrypted.dir");
+ BackupStoreDirectory dir(dir_file);
+ TEST_EQUAL(2, dir.GetNumberOfEntries());
+ BackupStoreDirectory::Entry* en = dir.FindEntryByID(0x2);
+ TEST_THAT(en != NULL);
+ if(en)
+ {
+ BackupStoreFilenameClear clear(en->GetName());
+ TEST_EQUAL("lovely_directory", clear.GetClearFilename());
}
}
diff --git a/test/backupstore/testfiles/encrypted.dir b/test/backupstore/testfiles/encrypted.dir
new file mode 100644
index 00000000..db46feca
--- /dev/null
+++ b/test/backupstore/testfiles/encrypted.dir
Binary files differ
diff --git a/test/crypto/testcrypto.cpp b/test/crypto/testcrypto.cpp
index 32d2efb8..200bdd0f 100644
--- a/test/crypto/testcrypto.cpp
+++ b/test/crypto/testcrypto.cpp
@@ -12,13 +12,15 @@
#include <string.h>
#include <openssl/rand.h>
-#include "Test.h"
#include "CipherContext.h"
#include "CipherBlowfish.h"
#include "CipherAES.h"
#include "CipherException.h"
+#include "CollectInBufferStream.h"
+#include "Guards.h"
#include "RollingChecksum.h"
#include "Random.h"
+#include "Test.h"
#include "MemLeakFindOn.h"
@@ -33,6 +35,12 @@
#define CHECKSUM_BLOCK_SIZE_LAST (CHECKSUM_BLOCK_SIZE_BASE + 64)
#define CHECKSUM_ROLLS 16
+// Copied from BackupClientCryptoKeys.h
+#define BACKUPCRYPTOKEYS_FILENAME_KEY_START 0
+#define BACKUPCRYPTOKEYS_FILENAME_KEY_LENGTH 56
+#define BACKUPCRYPTOKEYS_FILENAME_IV_START (0 + BACKUPCRYPTOKEYS_FILENAME_KEY_LENGTH)
+#define BACKUPCRYPTOKEYS_FILENAME_IV_LENGTH 8
+
void check_random_int(uint32_t max)
{
for(int c = 0; c < 1024; ++c)
@@ -262,6 +270,70 @@ int test(int argc, const char *argv[])
::printf("Skipping AES -- not supported by version of OpenSSL in use.\n");
#endif
+ // Test with known plaintext and ciphertext (correct algorithm used, etc)
+ {
+ FileStream keyfile("testfiles/bbackupd.keys");
+ // Ideally we would use a 448 bit (56 byte) key here, since that's what we do in
+ // real life, but unfortunately the OpenSSL command-line tool only supports 128-bit
+ // Blowfish keys, so it's hard to generate a reference ciphertext unless we restrict
+ // ourselves to what OpenSSL can support too.
+ // https://security.stackexchange.com/questions/25393/openssl-blowfish-key-limited-to-256-bits
+ char key[16], iv[BACKUPCRYPTOKEYS_FILENAME_IV_LENGTH];
+
+ if(!keyfile.ReadFullBuffer(key, sizeof(key), 0))
+ {
+ TEST_FAIL_WITH_MESSAGE("Failed to read full key length from file");
+ }
+
+ keyfile.Seek(BACKUPCRYPTOKEYS_FILENAME_KEY_LENGTH, IOStream::SeekType_Absolute);
+ if(!keyfile.ReadFullBuffer(iv, sizeof(iv), 0))
+ {
+ TEST_FAIL_WITH_MESSAGE("Failed to read full IV length from file");
+ }
+
+ CipherContext encryptor;
+ CipherContext decryptor;
+
+ encryptor.Reset();
+ encryptor.Init(CipherContext::Encrypt, CipherBlowfish(CipherDescription::Mode_CBC, key, sizeof(key)));
+ ASSERT(encryptor.GetIVLength() == sizeof(iv));
+ encryptor.SetIV(iv);
+
+ decryptor.Reset();
+ decryptor.Init(CipherContext::Decrypt, CipherBlowfish(CipherDescription::Mode_CBC, key, sizeof(key)));
+ ASSERT(decryptor.GetIVLength() == sizeof(iv));
+ decryptor.SetIV(iv);
+
+ // The encrypted file bfdlink.h.enc was generated with the following command:
+ // key=`dd if=bbackupd.keys bs=1 count=16 | hexdump -e '/1 "%02x"'`
+ // iv=`dd if=bbackupd.keys bs=1 skip=56 count=8 | hexdump -e '/1 "%02x"'`
+ // openssl enc -bf -in bfdlink.h -K $key -iv $iv
+ // And has MD5 checksum 586b65fdd07474bc139c0795d344d8ad
+ FileStream plaintext_file("testfiles/bfdlink.h", O_RDONLY);
+ FileStream ciphertext_file("testfiles/bfdlink.h.enc", O_RDONLY);
+
+ CollectInBufferStream plaintext, ciphertext;
+ plaintext_file.CopyStreamTo(plaintext);
+ ciphertext_file.CopyStreamTo(ciphertext);
+ plaintext.SetForReading();
+ ciphertext.SetForReading();
+
+ MemoryBlockGuard<void *> encrypted(
+ encryptor.MaxOutSizeForInBufferSize(ciphertext.GetSize()));
+
+ int encrypted_size = encryptor.TransformBlock(encrypted.GetPtr(),
+ encrypted.GetSize(), plaintext.GetBuffer(), plaintext.GetSize());
+ TEST_EQUAL(ciphertext.GetSize(), encrypted_size);
+ TEST_EQUAL(0, memcmp(encrypted.GetPtr(), ciphertext.GetBuffer(), encrypted_size));
+
+ MemoryBlockGuard<void *> decrypted(ciphertext.GetSize() + 16);
+
+ int decrypted_size = decryptor.TransformBlock(decrypted.GetPtr(),
+ decrypted.GetSize(), encrypted.GetPtr(), encrypted_size);
+ TEST_EQUAL(plaintext.GetSize(), decrypted_size);
+ TEST_EQUAL(0, memcmp(decrypted.GetPtr(), plaintext.GetBuffer(), decrypted_size));
+ }
+
::printf("Misc...\n");
// Check rolling checksums
uint8_t *checkdata_blk = (uint8_t *)malloc(CHECKSUM_DATA_SIZE);
diff --git a/test/crypto/testfiles/bbackupd.keys b/test/crypto/testfiles/bbackupd.keys
new file mode 100644
index 00000000..4c58fc22
--- /dev/null
+++ b/test/crypto/testfiles/bbackupd.keys
Binary files differ
diff --git a/test/crypto/testfiles/bfdlink.h b/test/crypto/testfiles/bfdlink.h
new file mode 100755
index 00000000..29eeb661
--- /dev/null
+++ b/test/crypto/testfiles/bfdlink.h
@@ -0,0 +1,555 @@
+/* bfdlink.h -- header file for BFD link routines
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+ Free Software Foundation, Inc.
+ Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef BFDLINK_H
+#define BFDLINK_H
+
+/* Which symbols to strip during a link. */
+enum bfd_link_strip
+{
+ strip_none, /* Don't strip any symbols. */
+ strip_debugger, /* Strip debugging symbols. */
+ strip_some, /* keep_hash is the list of symbols to keep. */
+ strip_all /* Strip all symbols. */
+};
+
+/* Which local symbols to discard during a link. This is irrelevant
+ if strip_all is used. */
+enum bfd_link_discard
+{
+ discard_none, /* Don't discard any locals. */
+ discard_l, /* Discard local temporary symbols. */
+ discard_all /* Discard all locals. */
+};
+
+/* These are the possible types of an entry in the BFD link hash
+ table. */
+
+enum bfd_link_hash_type
+{
+ bfd_link_hash_new, /* Symbol is new. */
+ bfd_link_hash_undefined, /* Symbol seen before, but undefined. */
+ bfd_link_hash_undefweak, /* Symbol is weak and undefined. */
+ bfd_link_hash_defined, /* Symbol is defined. */
+ bfd_link_hash_defweak, /* Symbol is weak and defined. */
+ bfd_link_hash_common, /* Symbol is common. */
+ bfd_link_hash_indirect, /* Symbol is an indirect link. */
+ bfd_link_hash_warning /* Like indirect, but warn if referenced. */
+};
+
+/* The linking routines use a hash table which uses this structure for
+ its elements. */
+
+struct bfd_link_hash_entry
+{
+ /* Base hash table entry structure. */
+ struct bfd_hash_entry root;
+ /* Type of this entry. */
+ enum bfd_link_hash_type type;
+
+ /* Undefined and common symbols are kept in a linked list through
+ this field. This field is not in the union because that would
+ force us to remove entries from the list when we changed their
+ type, which would force the list to be doubly linked, which would
+ waste more memory. When an undefined or common symbol is
+ created, it should be added to this list, the head of which is in
+ the link hash table itself. As symbols are defined, they need
+ not be removed from the list; anything which reads the list must
+ doublecheck the symbol type.
+
+ Weak symbols are not kept on this list.
+
+ Defined and defweak symbols use this field as a reference marker.
+ If the field is not NULL, or this structure is the tail of the
+ undefined symbol list, the symbol has been referenced. If the
+ symbol is undefined and becomes defined, this field will
+ automatically be non-NULL since the symbol will have been on the
+ undefined symbol list. */
+ struct bfd_link_hash_entry *next;
+ /* A union of information depending upon the type. */
+ union
+ {
+ /* Nothing is kept for bfd_hash_new. */
+ /* bfd_link_hash_undefined, bfd_link_hash_undefweak. */
+ struct
+ {
+ bfd *abfd; /* BFD symbol was found in. */
+ } undef;
+ /* bfd_link_hash_defined, bfd_link_hash_defweak. */
+ struct
+ {
+ bfd_vma value; /* Symbol value. */
+ asection *section; /* Symbol section. */
+ } def;
+ /* bfd_link_hash_indirect, bfd_link_hash_warning. */
+ struct
+ {
+ struct bfd_link_hash_entry *link; /* Real symbol. */
+ const char *warning; /* Warning (bfd_link_hash_warning only). */
+ } i;
+ /* bfd_link_hash_common. */
+ struct
+ {
+ /* The linker needs to know three things about common
+ symbols: the size, the alignment, and the section in
+ which the symbol should be placed. We store the size
+ here, and we allocate a small structure to hold the
+ section and the alignment. The alignment is stored as a
+ power of two. We don't store all the information
+ directly because we don't want to increase the size of
+ the union; this structure is a major space user in the
+ linker. */
+ bfd_size_type size; /* Common symbol size. */
+ struct bfd_link_hash_common_entry
+ {
+ unsigned int alignment_power; /* Alignment. */
+ asection *section; /* Symbol section. */
+ } *p;
+ } c;
+ } u;
+};
+
+/* This is the link hash table. It is a derived class of
+ bfd_hash_table. */
+
+struct bfd_link_hash_table
+{
+ /* The hash table itself. */
+ struct bfd_hash_table table;
+ /* The back end which created this hash table. This indicates the
+ type of the entries in the hash table, which is sometimes
+ important information when linking object files of different
+ types together. */
+ const bfd_target *creator;
+ /* A linked list of undefined and common symbols, linked through the
+ next field in the bfd_link_hash_entry structure. */
+ struct bfd_link_hash_entry *undefs;
+ /* Entries are added to the tail of the undefs list. */
+ struct bfd_link_hash_entry *undefs_tail;
+};
+
+/* Look up an entry in a link hash table. If FOLLOW is true, this
+ follows bfd_link_hash_indirect and bfd_link_hash_warning links to
+ the real symbol. */
+extern struct bfd_link_hash_entry *bfd_link_hash_lookup
+ PARAMS ((struct bfd_link_hash_table *, const char *, boolean create,
+ boolean copy, boolean follow));
+
+/* Look up an entry in the main linker hash table if the symbol might
+ be wrapped. This should only be used for references to an
+ undefined symbol, not for definitions of a symbol. */
+
+extern struct bfd_link_hash_entry *bfd_wrapped_link_hash_lookup
+ PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean, boolean,
+ boolean));
+
+/* Traverse a link hash table. */
+extern void bfd_link_hash_traverse
+ PARAMS ((struct bfd_link_hash_table *,
+ boolean (*) (struct bfd_link_hash_entry *, PTR),
+ PTR));
+
+/* Add an entry to the undefs list. */
+extern void bfd_link_add_undef
+ PARAMS ((struct bfd_link_hash_table *, struct bfd_link_hash_entry *));
+
+/* This structure holds all the information needed to communicate
+ between BFD and the linker when doing a link. */
+
+struct bfd_link_info
+{
+ /* Function callbacks. */
+ const struct bfd_link_callbacks *callbacks;
+ /* true if BFD should generate a relocateable object file. */
+ boolean relocateable;
+ /* true if BFD should generate relocation information in the final executable. */
+ boolean emitrelocations;
+ /* true if BFD should generate a "task linked" object file,
+ similar to relocatable but also with globals converted to statics. */
+ boolean task_link;
+ /* true if BFD should generate a shared object. */
+ boolean shared;
+ /* true if BFD should pre-bind symbols in a shared object. */
+ boolean symbolic;
+ /* true if shared objects should be linked directly, not shared. */
+ boolean static_link;
+ /* true if the output file should be in a traditional format. This
+ is equivalent to the setting of the BFD_TRADITIONAL_FORMAT flag
+ on the output file, but may be checked when reading the input
+ files. */
+ boolean traditional_format;
+ /* true if we want to produced optimized output files. This might
+ need much more time and therefore must be explicitly selected. */
+ boolean optimize;
+ /* true if BFD should generate errors for undefined symbols
+ even if generating a shared object. */
+ boolean no_undefined;
+ /* true if BFD should allow undefined symbols in shared objects even
+ when no_undefined is set to disallow undefined symbols. The net
+ result will be that undefined symbols in regular objects will
+ still trigger an error, but undefined symbols in shared objects
+ will be ignored. The implementation of no_undefined makes the
+ assumption that the runtime linker will choke on undefined
+ symbols. However there is at least one system (BeOS) where
+ undefined symbols in shared libraries is normal since the kernel
+ patches them at load time to select which function is most
+ appropriate for the current architecture. I.E. dynamically
+ select an appropriate memset function. Apparently it is also
+ normal for HPPA shared libraries to have undefined symbols. */
+ boolean allow_shlib_undefined;
+ /* Which symbols to strip. */
+ enum bfd_link_strip strip;
+ /* Which local symbols to discard. */
+ enum bfd_link_discard discard;
+ /* true if symbols should be retained in memory, false if they
+ should be freed and reread. */
+ boolean keep_memory;
+ /* The list of input BFD's involved in the link. These are chained
+ together via the link_next field. */
+ bfd *input_bfds;
+ /* If a symbol should be created for each input BFD, this is section
+ where those symbols should be placed. It must be a section in
+ the output BFD. It may be NULL, in which case no such symbols
+ will be created. This is to support CREATE_OBJECT_SYMBOLS in the
+ linker command language. */
+ asection *create_object_symbols_section;
+ /* Hash table handled by BFD. */
+ struct bfd_link_hash_table *hash;
+ /* Hash table of symbols to keep. This is NULL unless strip is
+ strip_some. */
+ struct bfd_hash_table *keep_hash;
+ /* true if every symbol should be reported back via the notice
+ callback. */
+ boolean notice_all;
+ /* Hash table of symbols to report back via the notice callback. If
+ this is NULL, and notice_all is false, then no symbols are
+ reported back. */
+ struct bfd_hash_table *notice_hash;
+ /* Hash table of symbols which are being wrapped (the --wrap linker
+ option). If this is NULL, no symbols are being wrapped. */
+ struct bfd_hash_table *wrap_hash;
+ /* If a base output file is wanted, then this points to it */
+ PTR base_file;
+
+ /* If non-zero, specifies that branches which are problematic for the
+ MPC860 C0 (or earlier) should be checked for and modified. It gives the
+ number of bytes that should be checked at the end of each text page. */
+ int mpc860c0;
+
+ /* The function to call when the executable or shared object is
+ loaded. */
+ const char *init_function;
+ /* The function to call when the executable or shared object is
+ unloaded. */
+ const char *fini_function;
+
+ /* true if the new ELF dynamic tags are enabled. */
+ boolean new_dtags;
+
+ /* May be used to set DT_FLAGS for ELF. */
+ bfd_vma flags;
+
+ /* May be used to set DT_FLAGS_1 for ELF. */
+ bfd_vma flags_1;
+};
+
+/* This structures holds a set of callback functions. These are
+ called by the BFD linker routines. The first argument to each
+ callback function is the bfd_link_info structure being used. Each
+ function returns a boolean value. If the function returns false,
+ then the BFD function which called it will return with a failure
+ indication. */
+
+struct bfd_link_callbacks
+{
+ /* A function which is called when an object is added from an
+ archive. ABFD is the archive element being added. NAME is the
+ name of the symbol which caused the archive element to be pulled
+ in. */
+ boolean (*add_archive_element) PARAMS ((struct bfd_link_info *,
+ bfd *abfd,
+ const char *name));
+ /* A function which is called when a symbol is found with multiple
+ definitions. NAME is the symbol which is defined multiple times.
+ OBFD is the old BFD, OSEC is the old section, OVAL is the old
+ value, NBFD is the new BFD, NSEC is the new section, and NVAL is
+ the new value. OBFD may be NULL. OSEC and NSEC may be
+ bfd_com_section or bfd_ind_section. */
+ boolean (*multiple_definition) PARAMS ((struct bfd_link_info *,
+ const char *name,
+ bfd *obfd,
+ asection *osec,
+ bfd_vma oval,
+ bfd *nbfd,
+ asection *nsec,
+ bfd_vma nval));
+ /* A function which is called when a common symbol is defined
+ multiple times. NAME is the symbol appearing multiple times.
+ OBFD is the BFD of the existing symbol; it may be NULL if this is
+ not known. OTYPE is the type of the existing symbol, which may
+ be bfd_link_hash_defined, bfd_link_hash_defweak,
+ bfd_link_hash_common, or bfd_link_hash_indirect. If OTYPE is
+ bfd_link_hash_common, OSIZE is the size of the existing symbol.
+ NBFD is the BFD of the new symbol. NTYPE is the type of the new
+ symbol, one of bfd_link_hash_defined, bfd_link_hash_common, or
+ bfd_link_hash_indirect. If NTYPE is bfd_link_hash_common, NSIZE
+ is the size of the new symbol. */
+ boolean (*multiple_common) PARAMS ((struct bfd_link_info *,
+ const char *name,
+ bfd *obfd,
+ enum bfd_link_hash_type otype,
+ bfd_vma osize,
+ bfd *nbfd,
+ enum bfd_link_hash_type ntype,
+ bfd_vma nsize));
+ /* A function which is called to add a symbol to a set. ENTRY is
+ the link hash table entry for the set itself (e.g.,
+ __CTOR_LIST__). RELOC is the relocation to use for an entry in
+ the set when generating a relocateable file, and is also used to
+ get the size of the entry when generating an executable file.
+ ABFD, SEC and VALUE identify the value to add to the set. */
+ boolean (*add_to_set) PARAMS ((struct bfd_link_info *,
+ struct bfd_link_hash_entry *entry,
+ bfd_reloc_code_real_type reloc,
+ bfd *abfd, asection *sec, bfd_vma value));
+ /* A function which is called when the name of a g++ constructor or
+ destructor is found. This is only called by some object file
+ formats. CONSTRUCTOR is true for a constructor, false for a
+ destructor. This will use BFD_RELOC_CTOR when generating a
+ relocateable file. NAME is the name of the symbol found. ABFD,
+ SECTION and VALUE are the value of the symbol. */
+ boolean (*constructor) PARAMS ((struct bfd_link_info *,
+ boolean constructor,
+ const char *name, bfd *abfd, asection *sec,
+ bfd_vma value));
+ /* A function which is called to issue a linker warning. For
+ example, this is called when there is a reference to a warning
+ symbol. WARNING is the warning to be issued. SYMBOL is the name
+ of the symbol which triggered the warning; it may be NULL if
+ there is none. ABFD, SECTION and ADDRESS identify the location
+ which trigerred the warning; either ABFD or SECTION or both may
+ be NULL if the location is not known. */
+ boolean (*warning) PARAMS ((struct bfd_link_info *,
+ const char *warning, const char *symbol,
+ bfd *abfd, asection *section,
+ bfd_vma address));
+ /* A function which is called when a relocation is attempted against
+ an undefined symbol. NAME is the symbol which is undefined.
+ ABFD, SECTION and ADDRESS identify the location from which the
+ reference is made. FATAL indicates whether an undefined symbol is
+ a fatal error or not. In some cases SECTION may be NULL. */
+ boolean (*undefined_symbol) PARAMS ((struct bfd_link_info *,
+ const char *name, bfd *abfd,
+ asection *section,
+ bfd_vma address,
+ boolean fatal));
+ /* A function which is called when a reloc overflow occurs. NAME is
+ the name of the symbol or section the reloc is against,
+ RELOC_NAME is the name of the relocation, and ADDEND is any
+ addend that is used. ABFD, SECTION and ADDRESS identify the
+ location at which the overflow occurs; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ boolean (*reloc_overflow) PARAMS ((struct bfd_link_info *,
+ const char *name,
+ const char *reloc_name, bfd_vma addend,
+ bfd *abfd, asection *section,
+ bfd_vma address));
+ /* A function which is called when a dangerous reloc is performed.
+ The canonical example is an a29k IHCONST reloc which does not
+ follow an IHIHALF reloc. MESSAGE is an appropriate message.
+ ABFD, SECTION and ADDRESS identify the location at which the
+ problem occurred; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ boolean (*reloc_dangerous) PARAMS ((struct bfd_link_info *,
+ const char *message,
+ bfd *abfd, asection *section,
+ bfd_vma address));
+ /* A function which is called when a reloc is found to be attached
+ to a symbol which is not being written out. NAME is the name of
+ the symbol. ABFD, SECTION and ADDRESS identify the location of
+ the reloc; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ boolean (*unattached_reloc) PARAMS ((struct bfd_link_info *,
+ const char *name,
+ bfd *abfd, asection *section,
+ bfd_vma address));
+ /* A function which is called when a symbol in notice_hash is
+ defined or referenced. NAME is the symbol. ABFD, SECTION and
+ ADDRESS are the value of the symbol. If SECTION is
+ bfd_und_section, this is a reference. */
+ boolean (*notice) PARAMS ((struct bfd_link_info *, const char *name,
+ bfd *abfd, asection *section, bfd_vma address));
+};
+
+/* The linker builds link_order structures which tell the code how to
+ include input data in the output file. */
+
+/* These are the types of link_order structures. */
+
+enum bfd_link_order_type
+{
+ bfd_undefined_link_order, /* Undefined. */
+ bfd_indirect_link_order, /* Built from a section. */
+ bfd_fill_link_order, /* Fill with a 16 bit constant. */
+ bfd_data_link_order, /* Set to explicit data. */
+ bfd_section_reloc_link_order, /* Relocate against a section. */
+ bfd_symbol_reloc_link_order /* Relocate against a symbol. */
+};
+
+/* This is the link_order structure itself. These form a chain
+ attached to the section whose contents they are describing. */
+
+struct bfd_link_order
+{
+ /* Next link_order in chain. */
+ struct bfd_link_order *next;
+ /* Type of link_order. */
+ enum bfd_link_order_type type;
+ /* Offset within output section. */
+ bfd_vma offset;
+ /* Size within output section. */
+ bfd_size_type size;
+ /* Type specific information. */
+ union
+ {
+ struct
+ {
+ /* Section to include. If this is used, then
+ section->output_section must be the section the
+ link_order is attached to, section->output_offset must
+ equal the link_order offset field, and section->_raw_size
+ must equal the link_order size field. Maybe these
+ restrictions should be relaxed someday. */
+ asection *section;
+ } indirect;
+ struct
+ {
+ /* Value to fill with. */
+ unsigned int value;
+ } fill;
+ struct
+ {
+ /* Data to put into file. The size field gives the number
+ of bytes which this field points to. */
+ bfd_byte *contents;
+ } data;
+ struct
+ {
+ /* Description of reloc to generate. Used for
+ bfd_section_reloc_link_order and
+ bfd_symbol_reloc_link_order. */
+ struct bfd_link_order_reloc *p;
+ } reloc;
+ } u;
+};
+
+/* A linker order of type bfd_section_reloc_link_order or
+ bfd_symbol_reloc_link_order means to create a reloc against a
+ section or symbol, respectively. This is used to implement -Ur to
+ generate relocs for the constructor tables. The
+ bfd_link_order_reloc structure describes the reloc that BFD should
+ create. It is similar to a arelent, but I didn't use arelent
+ because the linker does not know anything about most symbols, and
+ any asymbol structure it creates will be partially meaningless.
+ This information could logically be in the bfd_link_order struct,
+ but I didn't want to waste the space since these types of relocs
+ are relatively rare. */
+
+struct bfd_link_order_reloc
+{
+ /* Reloc type. */
+ bfd_reloc_code_real_type reloc;
+
+ union
+ {
+ /* For type bfd_section_reloc_link_order, this is the section
+ the reloc should be against. This must be a section in the
+ output BFD, not any of the input BFDs. */
+ asection *section;
+ /* For type bfd_symbol_reloc_link_order, this is the name of the
+ symbol the reloc should be against. */
+ const char *name;
+ } u;
+
+ /* Addend to use. The object file should contain zero. The BFD
+ backend is responsible for filling in the contents of the object
+ file correctly. For some object file formats (e.g., COFF) the
+ addend must be stored into in the object file, and for some
+ (e.g., SPARC a.out) it is kept in the reloc. */
+ bfd_vma addend;
+};
+
+/* Allocate a new link_order for a section. */
+extern struct bfd_link_order *bfd_new_link_order PARAMS ((bfd *, asection *));
+
+/* These structures are used to describe version information for the
+ ELF linker. These structures could be manipulated entirely inside
+ BFD, but it would be a pain. Instead, the regular linker sets up
+ these structures, and then passes them into BFD. */
+
+/* Regular expressions for a version. */
+
+struct bfd_elf_version_expr
+{
+ /* Next regular expression for this version. */
+ struct bfd_elf_version_expr *next;
+ /* Regular expression. */
+ const char *pattern;
+ /* Matching function. */
+ int (*match) PARAMS((struct bfd_elf_version_expr *, const char *));
+};
+
+/* Version dependencies. */
+
+struct bfd_elf_version_deps
+{
+ /* Next dependency for this version. */
+ struct bfd_elf_version_deps *next;
+ /* The version which this version depends upon. */
+ struct bfd_elf_version_tree *version_needed;
+};
+
+/* A node in the version tree. */
+
+struct bfd_elf_version_tree
+{
+ /* Next version. */
+ struct bfd_elf_version_tree *next;
+ /* Name of this version. */
+ const char *name;
+ /* Version number. */
+ unsigned int vernum;
+ /* Regular expressions for global symbols in this version. */
+ struct bfd_elf_version_expr *globals;
+ /* Regular expressions for local symbols in this version. */
+ struct bfd_elf_version_expr *locals;
+ /* List of versions which this version depends upon. */
+ struct bfd_elf_version_deps *deps;
+ /* Index of the version name. This is used within BFD. */
+ unsigned int name_indx;
+ /* Whether this version tree was used. This is used within BFD. */
+ int used;
+};
+
+#endif
diff --git a/test/crypto/testfiles/bfdlink.h.enc b/test/crypto/testfiles/bfdlink.h.enc
new file mode 100644
index 00000000..ddc7b01e
--- /dev/null
+++ b/test/crypto/testfiles/bfdlink.h.enc
Binary files differ