mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Merge branch 'thirdparty_dev' into dev + Plus minimal changes in code needed to make it compile and pass unit tests + Other changes are pending
What is pending: - AES is now again compiled using Borland compiler (previously by VS) - Add support for HW SHA What is lost and needs to be re-implemented: - Custom fixes for vulnerabilities fixed in PuTTY 0.71 (will be added implicitly, once merge of PuTTY 0.71 is complete) - callback.c is now locked more heavily - should be optimized. Note: Or would-be thread-safety changes to callback.c were obviously not thread safe as they would call callbacks for other sessions from thread for another session (as there's only one callback queue) - This needs to be solved # Conflicts: # source/putty/WINDOWS/wingss.c # source/putty/WINDOWS/winhsock.c # source/putty/WINDOWS/winnet.c # source/putty/callback.c # source/putty/proxy.c # source/putty/putty.h # source/putty/ssh.c # source/putty/ssh.h # source/putty/sshaes.c # source/putty/sshdh.c # source/putty/sshpubk.c # source/putty/sshrsa.c # source/putty/sshsh256.c # source/putty/version.h # source/putty/x11fwd.c Source commit: d7d9798d5b0c01f4a797d0a2ace8856e32909158
This commit is contained in:
@@ -123,6 +123,9 @@
|
||||
<BuildOrder>27</BuildOrder>
|
||||
<BuildOrder>11</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\marshal.c">
|
||||
<BuildOrder>55</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\misc.c">
|
||||
<BuildOrder>26</BuildOrder>
|
||||
<BuildOrder>14</BuildOrder>
|
||||
@@ -133,6 +136,9 @@
|
||||
<CppCompile Include="putty\noshare.c">
|
||||
<BuildOrder>41</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\nullplug.c">
|
||||
<BuildOrder>56</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\pgssapi.c">
|
||||
<BuildOrder>37</BuildOrder>
|
||||
</CppCompile>
|
||||
@@ -147,6 +153,21 @@
|
||||
<BuildOrder>23</BuildOrder>
|
||||
<BuildOrder>19</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh1bpp.c">
|
||||
<BuildOrder>53</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh1censor.c">
|
||||
<BuildOrder>57</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh2bpp.c">
|
||||
<BuildOrder>54</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh2bpp-bare.c">
|
||||
<BuildOrder>59</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh2censor.c">
|
||||
<BuildOrder>58</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\sshaes.c">
|
||||
<BuildOrder>26</BuildOrder>
|
||||
<BuildOrder>22</BuildOrder>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
#define sha1_ctx SHA_State
|
||||
#define sha1_begin(ctx) putty_SHA_Init(ctx)
|
||||
#define sha1_hash(buf, len, ctx) SHA_Bytes(ctx, buf, len)
|
||||
#define sha1_hash(buf, len, ctx) put_data(ctx, buf, len)
|
||||
#define sha1_end(dig, ctx) putty_SHA_Final(ctx, dig)
|
||||
|
||||
#define IN_BLOCK_LENGTH 64
|
||||
@@ -156,7 +156,7 @@ static void hmac_sha1_end(unsigned char mac[], unsigned long mac_len, hmac_ctx c
|
||||
|
||||
void aes_set_encrypt_key(const unsigned char in_key[], unsigned int klen, void * cx)
|
||||
{
|
||||
call_aes_setup(cx, BLOCK_SIZE, const_cast<unsigned char *>(in_key), klen);
|
||||
call_aes_setup(cx, const_cast<unsigned char *>(in_key), klen);
|
||||
}
|
||||
|
||||
void aes_encrypt_block(const unsigned char in_blk[], unsigned char out_blk[], void * cx)
|
||||
@@ -672,7 +672,7 @@ TEncryption::~TEncryption()
|
||||
//---------------------------------------------------------------------------
|
||||
void TEncryption::SetSalt()
|
||||
{
|
||||
aes_iv(FContext, reinterpret_cast<unsigned char *>(FSalt.c_str()));
|
||||
aes_iv(FContext, reinterpret_cast<const void *>(FSalt.c_str()));
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TEncryption::NeedSalt()
|
||||
|
||||
@@ -82,8 +82,8 @@ extern "C" char * do_select(Plug plug, SOCKET skt, int startup)
|
||||
{
|
||||
// If it is not SSH/PFwd plug, then it must be Proxy plug.
|
||||
// Get SSH/PFwd plug which it wraps.
|
||||
Proxy_Socket ProxySocket = ((Proxy_Plug)plug)->proxy_socket;
|
||||
plug = ProxySocket->plug;
|
||||
ProxySocket * AProxySocket = get_proxy_plug_socket(plug);
|
||||
plug = AProxySocket->plug;
|
||||
}
|
||||
|
||||
bool pfwd = is_pfwd(plug);
|
||||
@@ -108,7 +108,7 @@ extern "C" char * do_select(Plug plug, SOCKET skt, int startup)
|
||||
return NULL;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int from_backend(void * frontend, int is_stderr, const char * data, int datalen)
|
||||
int from_backend(void * frontend, int is_stderr, const void * data, int datalen)
|
||||
{
|
||||
DebugAssert(frontend);
|
||||
if (is_stderr >= 0)
|
||||
@@ -119,12 +119,12 @@ int from_backend(void * frontend, int is_stderr, const char * data, int datalen)
|
||||
else
|
||||
{
|
||||
DebugAssert(is_stderr == -1);
|
||||
((TSecureShell *)frontend)->CWrite(data, datalen);
|
||||
((TSecureShell *)frontend)->CWrite(reinterpret_cast<const char *>(data), datalen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int from_backend_untrusted(void * /*frontend*/, const char * /*data*/, int /*len*/)
|
||||
int from_backend_untrusted(void * /*frontend*/, const void * /*data*/, int /*len*/)
|
||||
{
|
||||
// currently used with authentication banner only,
|
||||
// for which we have own interface display_banner
|
||||
@@ -136,7 +136,7 @@ int from_backend_eof(void * /*frontend*/)
|
||||
return FALSE;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int get_userpass_input(prompts_t * p, const unsigned char * /*in*/, int /*inlen*/)
|
||||
int get_userpass_input(prompts_t * p, bufchain * DebugUsedArg(input))
|
||||
{
|
||||
DebugAssert(p != NULL);
|
||||
TSecureShell * SecureShell = reinterpret_cast<TSecureShell *>(p->frontend);
|
||||
@@ -682,8 +682,7 @@ void SaveKey(TKeyType KeyType, const UnicodeString & FileName,
|
||||
void FreeKey(TPrivateKey * PrivateKey)
|
||||
{
|
||||
struct ssh2_userkey * Ssh2Key = reinterpret_cast<struct ssh2_userkey *>(PrivateKey);
|
||||
Ssh2Key->alg->freekey(Ssh2Key->data);
|
||||
sfree(Ssh2Key->comment);
|
||||
ssh_key_free(Ssh2Key->key);
|
||||
sfree(Ssh2Key);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -698,9 +697,8 @@ RawByteString LoadPublicKey(const UnicodeString & FileName, UnicodeString & Algo
|
||||
int PublicKeyLen = 0;
|
||||
char * CommentStr = NULL;
|
||||
const char * ErrorStr = NULL;
|
||||
unsigned char * PublicKeyPtr =
|
||||
ssh2_userkey_loadpub(KeyFile, &AlgorithmStr, &PublicKeyLen, &CommentStr, &ErrorStr);
|
||||
if (PublicKeyPtr == NULL)
|
||||
strbuf * PublicKeyBuf = strbuf_new();
|
||||
if (!ssh2_userkey_loadpub(KeyFile, &AlgorithmStr, BinarySink_UPCAST(PublicKeyBuf), &CommentStr, &ErrorStr))
|
||||
{
|
||||
UnicodeString Error = UnicodeString(AnsiString(ErrorStr));
|
||||
throw Exception(Error);
|
||||
@@ -709,8 +707,8 @@ RawByteString LoadPublicKey(const UnicodeString & FileName, UnicodeString & Algo
|
||||
sfree(AlgorithmStr);
|
||||
Comment = UnicodeString(AnsiString(CommentStr));
|
||||
sfree(CommentStr);
|
||||
Result = RawByteString(reinterpret_cast<char *>(PublicKeyPtr), PublicKeyLen);
|
||||
free(PublicKeyPtr);
|
||||
Result = RawByteString(reinterpret_cast<char *>(PublicKeyBuf->s), PublicKeyBuf->len);
|
||||
strbuf_free(PublicKeyBuf);
|
||||
}
|
||||
__finally
|
||||
{
|
||||
@@ -749,7 +747,7 @@ bool __fastcall HasGSSAPI(UnicodeString CustomPath)
|
||||
Ssh_gss_ctx ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
has =
|
||||
((library->acquire_cred(library, &ctx) == SSH_GSS_OK) &&
|
||||
((library->acquire_cred(library, &ctx, NULL) == SSH_GSS_OK) &&
|
||||
(library->release_cred(library, &ctx) == SSH_GSS_OK)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
@@ -771,7 +769,7 @@ static void __fastcall DoNormalizeFingerprint(UnicodeString & Fingerprint, Unico
|
||||
{
|
||||
const wchar_t NormalizedSeparator = L'-';
|
||||
const int MaxCount = 10;
|
||||
const ssh_signkey * SignKeys[MaxCount];
|
||||
const ssh_keyalg * SignKeys[MaxCount];
|
||||
int Count = LENOF(SignKeys);
|
||||
// We may use find_pubkey_alg, but it gets complicated with normalized fingerprint
|
||||
// as the names have different number of dashes
|
||||
@@ -779,8 +777,8 @@ static void __fastcall DoNormalizeFingerprint(UnicodeString & Fingerprint, Unico
|
||||
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
const ssh_signkey * SignKey = SignKeys[Index];
|
||||
UnicodeString Name = UnicodeString(SignKey->name);
|
||||
const ssh_keyalg * SignKey = SignKeys[Index];
|
||||
UnicodeString Name = UnicodeString(SignKey->ssh_id);
|
||||
if (StartsStr(Name + L" ", Fingerprint))
|
||||
{
|
||||
int LenStart = Name.Length() + 1;
|
||||
@@ -794,13 +792,13 @@ static void __fastcall DoNormalizeFingerprint(UnicodeString & Fingerprint, Unico
|
||||
Fingerprint.Delete(LenStart + 1, Space - LenStart);
|
||||
// noop for SHA256 fingerprints
|
||||
Fingerprint = ReplaceChar(Fingerprint, L':', NormalizedSeparator);
|
||||
KeyType = UnicodeString(SignKey->keytype);
|
||||
KeyType = UnicodeString(SignKey->cache_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (StartsStr(Name + NormalizedSeparator, Fingerprint))
|
||||
{
|
||||
KeyType = UnicodeString(SignKey->keytype);
|
||||
KeyType = UnicodeString(SignKey->cache_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -845,16 +843,15 @@ void __fastcall DllHijackingProtection()
|
||||
dll_hijacking_protection();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const struct ssh_signkey *& Algorithm)
|
||||
UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const struct ssh_keyalg *& Algorithm)
|
||||
{
|
||||
UTF8String UtfLine = UTF8String(Line);
|
||||
char * AlgorithmName = NULL;
|
||||
int PubBlobLen = 0;
|
||||
char * CommentPtr = NULL;
|
||||
const char * ErrorStr = NULL;
|
||||
unsigned char * PubBlob = openssh_loadpub_line(UtfLine.c_str(), &AlgorithmName, &PubBlobLen, &CommentPtr, &ErrorStr);
|
||||
strbuf * PubBlobBuf = strbuf_new();
|
||||
UnicodeString Result;
|
||||
if (PubBlob == NULL)
|
||||
if (!openssh_loadpub_line(UtfLine.c_str(), &AlgorithmName, BinarySink_UPCAST(PubBlobBuf), &CommentPtr, &ErrorStr))
|
||||
{
|
||||
throw Exception(UnicodeString(ErrorStr));
|
||||
}
|
||||
@@ -868,19 +865,20 @@ UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const s
|
||||
throw Exception(FORMAT(L"Unknown public key algorithm \"%s\".", (AlgorithmName)));
|
||||
}
|
||||
|
||||
void * Key = Algorithm->newkey(Algorithm, reinterpret_cast<const char*>(PubBlob), PubBlobLen);
|
||||
ptrlen PtrLen = { PubBlobBuf->s, PubBlobBuf->len };
|
||||
ssh_key * Key = Algorithm->new_pub(Algorithm, PtrLen);
|
||||
if (Key == NULL)
|
||||
{
|
||||
throw Exception(L"Invalid public key.");
|
||||
}
|
||||
char * FmtKey = Algorithm->fmtkey(Key);
|
||||
char * FmtKey = Algorithm->cache_str(Key);
|
||||
Result = UnicodeString(FmtKey);
|
||||
sfree(FmtKey);
|
||||
Algorithm->freekey(Key);
|
||||
}
|
||||
__finally
|
||||
{
|
||||
sfree(PubBlob);
|
||||
strbuf_free(PubBlobBuf);
|
||||
sfree(AlgorithmName);
|
||||
sfree(CommentPtr);
|
||||
}
|
||||
@@ -891,27 +889,27 @@ UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const s
|
||||
UnicodeString __fastcall GetKeyTypeHuman(const UnicodeString & KeyType)
|
||||
{
|
||||
UnicodeString Result;
|
||||
if (KeyType == ssh_dss.keytype)
|
||||
if (KeyType == ssh_dss.cache_id)
|
||||
{
|
||||
Result = L"DSA";
|
||||
}
|
||||
else if (KeyType == ssh_rsa.keytype)
|
||||
else if (KeyType == ssh_rsa.cache_id)
|
||||
{
|
||||
Result = L"RSA";
|
||||
}
|
||||
else if (KeyType == ssh_ecdsa_ed25519.keytype)
|
||||
else if (KeyType == ssh_ecdsa_ed25519.cache_id)
|
||||
{
|
||||
Result = L"Ed25519";
|
||||
}
|
||||
else if (KeyType == ssh_ecdsa_nistp256.keytype)
|
||||
else if (KeyType == ssh_ecdsa_nistp256.cache_id)
|
||||
{
|
||||
Result = L"ECDSA/nistp256";
|
||||
}
|
||||
else if (KeyType == ssh_ecdsa_nistp384.keytype)
|
||||
else if (KeyType == ssh_ecdsa_nistp384.cache_id)
|
||||
{
|
||||
Result = L"ECDSA/nistp384";
|
||||
}
|
||||
else if (KeyType == ssh_ecdsa_nistp521.keytype)
|
||||
else if (KeyType == ssh_ecdsa_nistp521.cache_id)
|
||||
{
|
||||
Result = L"ECDSA/nistp521";
|
||||
}
|
||||
@@ -968,14 +966,14 @@ TStrings * SshHostKeyList()
|
||||
{
|
||||
std::unique_ptr<TStrings> Result(new TStringList());
|
||||
const int MaxCount = 10;
|
||||
const ssh_signkey * SignKeys[MaxCount];
|
||||
const ssh_keyalg * SignKeys[MaxCount];
|
||||
int Count = LENOF(SignKeys);
|
||||
get_hostkey_algs(&Count, SignKeys);
|
||||
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
const ssh_signkey * SignKey = SignKeys[Index];
|
||||
UnicodeString Name = UnicodeString(SignKey->name);
|
||||
const ssh_keyalg * SignKey = SignKeys[Index];
|
||||
UnicodeString Name = UnicodeString(SignKey->ssh_id);
|
||||
Result->Add(Name);
|
||||
}
|
||||
return Result.release();
|
||||
|
||||
@@ -20,6 +20,8 @@ extern "C"
|
||||
// Defined in misc.h - Conflicts with std::min/max
|
||||
#undef min
|
||||
#undef max
|
||||
// Defined in marshal.h - Conflicts with xml.xmldom.hpp
|
||||
#undef get_data
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
@@ -34,7 +34,7 @@ UnicodeString __fastcall Sha256(const char * Data, size_t Size);
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall DllHijackingProtection();
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const struct ssh_signkey *& Algorithm);
|
||||
UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const struct ssh_keyalg *& Algorithm);
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall GetKeyTypeHuman(const UnicodeString & KeyType);
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -1829,9 +1829,10 @@ bool __fastcall TSecureShell::EnumNetworkEvents(SOCKET Socket, WSANETWORKEVENTS
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
bool Result =
|
||||
FLAGSET(Events.lNetworkEvents, FD_READ) ||
|
||||
FLAGSET(Events.lNetworkEvents, FD_CLOSE);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TSecureShell::HandleNetworkEvents(SOCKET Socket, WSANETWORKEVENTS & Events)
|
||||
@@ -1898,19 +1899,31 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
|
||||
Handles = sresize(Handles, HandleCount + 1, HANDLE);
|
||||
Handles[HandleCount] = FSocketEvent;
|
||||
unsigned int Timeout = MSec;
|
||||
if (toplevel_callback_pending())
|
||||
{
|
||||
Timeout = 0;
|
||||
}
|
||||
|
||||
unsigned int WaitResult;
|
||||
do
|
||||
{
|
||||
unsigned int TimeoutStep = std::min(GUIUpdateInterval, Timeout);
|
||||
if (toplevel_callback_pending())
|
||||
{
|
||||
TimeoutStep = 0;
|
||||
}
|
||||
Timeout -= TimeoutStep;
|
||||
WaitResult = WaitForMultipleObjects(HandleCount + 1, Handles, FALSE, TimeoutStep);
|
||||
FUI->ProcessGUI();
|
||||
} while ((WaitResult == WAIT_TIMEOUT) && (Timeout > 0));
|
||||
// run_toplevel_callbacks can cause processing of pending raw data, so:
|
||||
// 1) Check for changes in our pending buffer - wait criteria in Receive()
|
||||
int PrevDataLen = (-static_cast<int>(OutLen) + static_cast<int>(PendLen));
|
||||
// 2) Changes in session state - wait criteria in Init()
|
||||
bool PrevSessionState = get_ssh_state_session(FBackendHandle);
|
||||
if (run_toplevel_callbacks() &&
|
||||
(((-static_cast<int>(OutLen) + static_cast<int>(PendLen)) > PrevDataLen) ||
|
||||
(PrevSessionState != get_ssh_state_session(FBackendHandle))))
|
||||
{
|
||||
// Note that we still may process new network event now
|
||||
Result = true;
|
||||
}
|
||||
} while ((WaitResult == WAIT_TIMEOUT) && (Timeout > 0) && !Result);
|
||||
|
||||
if (WaitResult < WAIT_OBJECT_0 + HandleCount)
|
||||
{
|
||||
@@ -1974,7 +1987,6 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
|
||||
sfree(Handles);
|
||||
}
|
||||
|
||||
run_toplevel_callbacks();
|
||||
|
||||
unsigned int TicksAfter = GetTickCount();
|
||||
// ticks wraps once in 49.7 days
|
||||
@@ -2193,7 +2205,7 @@ void __fastcall TPasteKeyHandler::Paste(TObject * /*Sender*/, unsigned int & Ans
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct ssh_signkey * Algorithm;
|
||||
const struct ssh_keyalg * Algorithm;
|
||||
try
|
||||
{
|
||||
UnicodeString Key = ParseOpenSshPubLine(ClipboardText, Algorithm);
|
||||
|
||||
@@ -4369,12 +4369,12 @@ void __fastcall TStoredSessionList::ImportFromKnownHosts(TStrings * Lines)
|
||||
}
|
||||
}
|
||||
|
||||
const struct ssh_signkey * Algorithm;
|
||||
const struct ssh_keyalg * Algorithm;
|
||||
UnicodeString Key = ParseOpenSshPubLine(Line, Algorithm);
|
||||
UnicodeString KeyKey =
|
||||
FORMAT(L"%s@%d:%s", (Algorithm->keytype, SessionData->PortNumber, HostNameStr));
|
||||
FORMAT(L"%s@%d:%s", (Algorithm->cache_id, SessionData->PortNumber, HostNameStr));
|
||||
UnicodeString HostKey =
|
||||
FORMAT(L"%s:%s=%s", (Algorithm->name, KeyKey, Key));
|
||||
FORMAT(L"%s:%s=%s", (Algorithm->ssh_id, KeyKey, Key));
|
||||
UnicodeString HostKeyList = SessionData->HostKey;
|
||||
AddToList(HostKeyList, HostKey, L";");
|
||||
SessionData->HostKey = HostKeyList;
|
||||
|
||||
3
source/putty/be_misc.c
vendored
3
source/putty/be_misc.c
vendored
@@ -64,7 +64,8 @@ void log_proxy_stderr(Plug plug, bufchain *buf, const void *vdata, int len)
|
||||
const char *data = (const char *)vdata;
|
||||
int pos = 0;
|
||||
int msglen;
|
||||
char *nlpos, *msg, *fullmsg;
|
||||
const char *nlpos;
|
||||
char *msg, *fullmsg;
|
||||
|
||||
/*
|
||||
* This helper function allows us to collect the data written to a
|
||||
|
||||
110
source/putty/callback.c
vendored
110
source/putty/callback.c
vendored
@@ -14,7 +14,7 @@ struct callback {
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
struct callback *cbhead = NULL, *cbtail = NULL;
|
||||
struct callback *cbcurr = NULL, *cbhead = NULL, *cbtail = NULL;
|
||||
|
||||
toplevel_callback_notify_fn_t notify_frontend = NULL;
|
||||
void *frontend = NULL;
|
||||
@@ -28,7 +28,48 @@ void request_callback_notifications(toplevel_callback_notify_fn_t fn,
|
||||
MPEXT_PUTTY_SECTION_LEAVE;
|
||||
}
|
||||
|
||||
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
|
||||
static void run_idempotent_callback(void *ctx)
|
||||
{
|
||||
struct IdempotentCallback *ic = (struct IdempotentCallback *)ctx;
|
||||
ic->queued = FALSE;
|
||||
ic->fn(ic->ctx);
|
||||
}
|
||||
|
||||
void queue_idempotent_callback(struct IdempotentCallback *ic)
|
||||
{
|
||||
if (ic->queued)
|
||||
return;
|
||||
ic->queued = TRUE;
|
||||
queue_toplevel_callback(run_idempotent_callback, ic);
|
||||
}
|
||||
|
||||
void delete_callbacks_for_context(void *ctx)
|
||||
{
|
||||
struct callback *newhead, *newtail;
|
||||
|
||||
newhead = newtail = NULL;
|
||||
while (cbhead) {
|
||||
struct callback *cb = cbhead;
|
||||
cbhead = cbhead->next;
|
||||
if (cb->ctx == ctx ||
|
||||
(cb->fn == run_idempotent_callback &&
|
||||
((struct IdempotentCallback *)cb->ctx)->ctx == ctx)) {
|
||||
sfree(cb);
|
||||
} else {
|
||||
if (!newhead)
|
||||
newhead = cb;
|
||||
else
|
||||
newtail->next = cb;
|
||||
|
||||
newtail = cb;
|
||||
}
|
||||
}
|
||||
|
||||
cbhead = newhead;
|
||||
cbtail = newtail;
|
||||
}
|
||||
|
||||
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
|
||||
{
|
||||
struct callback *cb;
|
||||
|
||||
@@ -37,10 +78,18 @@ void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
|
||||
cb->fn = fn;
|
||||
cb->ctx = ctx;
|
||||
|
||||
/* If the front end has requested notification of pending
|
||||
/*
|
||||
* If the front end has requested notification of pending
|
||||
* callbacks, and we didn't already have one queued, let it know
|
||||
* we do have one now. */
|
||||
if (notify_frontend && !cbhead)
|
||||
* we do have one now.
|
||||
*
|
||||
* If cbcurr is non-NULL, i.e. we are actually in the middle of
|
||||
* executing a callback right now, then we count that as the queue
|
||||
* already having been non-empty. That saves the front end getting
|
||||
* a constant stream of needless re-notifications if the last
|
||||
* callback keeps re-scheduling itself.
|
||||
*/
|
||||
if (notify_frontend && !cbhead && !cbcurr)
|
||||
notify_frontend(frontend);
|
||||
|
||||
if (cbtail)
|
||||
@@ -52,47 +101,38 @@ void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
|
||||
MPEXT_PUTTY_SECTION_LEAVE;
|
||||
}
|
||||
|
||||
void run_toplevel_callbacks(void)
|
||||
int run_toplevel_callbacks(void)
|
||||
{
|
||||
int done_something = FALSE;
|
||||
MPEXT_PUTTY_SECTION_ENTER;
|
||||
|
||||
if (cbhead) {
|
||||
struct callback *cb = cbhead;
|
||||
#ifdef MPEXT
|
||||
toplevel_callback_fn_t fn = cb->fn;
|
||||
void * ctx = cb->ctx;
|
||||
cbhead = cb->next;
|
||||
if (!cbhead)
|
||||
cbtail = NULL;
|
||||
cbhead = cb->next;
|
||||
sfree(cb);
|
||||
MPEXT_PUTTY_SECTION_LEAVE;
|
||||
fn(ctx);
|
||||
#else
|
||||
/*
|
||||
* Careful ordering here. We call the function _before_
|
||||
* advancing cbhead (though, of course, we must free cb
|
||||
* _after_ advancing it). This means that if the very last
|
||||
* callback schedules another callback, cbhead does not become
|
||||
* NULL at any point, and so the frontend notification
|
||||
* function won't be needlessly pestered.
|
||||
* Transfer the head callback into cbcurr to indicate that
|
||||
* it's being executed. Then operations which transform the
|
||||
* queue, like delete_callbacks_for_context, can proceed as if
|
||||
* it's not there.
|
||||
*/
|
||||
cb->fn(cb->ctx);
|
||||
cbhead = cb->next;
|
||||
sfree(cb);
|
||||
cbcurr = cbhead;
|
||||
cbhead = cbhead->next;
|
||||
if (!cbhead)
|
||||
cbtail = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now run the callback, and then clear it out of cbcurr.
|
||||
*/
|
||||
cbcurr->fn(cbcurr->ctx);
|
||||
sfree(cbcurr);
|
||||
cbcurr = NULL;
|
||||
|
||||
done_something = TRUE;
|
||||
}
|
||||
#ifdef MPEXT
|
||||
else
|
||||
{
|
||||
MPEXT_PUTTY_SECTION_LEAVE;
|
||||
}
|
||||
#endif
|
||||
MPEXT_PUTTY_SECTION_LEAVE;
|
||||
return done_something;
|
||||
}
|
||||
|
||||
int toplevel_callback_pending(void)
|
||||
{
|
||||
// MP does not have to be guarded
|
||||
return cbhead != NULL;
|
||||
return cbcurr != NULL || cbhead != NULL;
|
||||
}
|
||||
|
||||
151
source/putty/conf.c
vendored
151
source/putty/conf.c
vendored
@@ -469,179 +469,88 @@ void conf_set_fontspec(Conf *conf, int primary, const FontSpec *value)
|
||||
conf_insert(conf, entry);
|
||||
}
|
||||
|
||||
int conf_serialised_size(Conf *conf)
|
||||
void conf_serialise(BinarySink *bs, Conf *conf)
|
||||
{
|
||||
int i;
|
||||
struct conf_entry *entry;
|
||||
int size = 0;
|
||||
|
||||
for (i = 0; (entry = index234(conf->tree, i)) != NULL; i++) {
|
||||
size += 4; /* primary key */
|
||||
put_uint32(bs, entry->key.primary);
|
||||
|
||||
switch (subkeytypes[entry->key.primary]) {
|
||||
case TYPE_INT:
|
||||
size += 4;
|
||||
put_uint32(bs, entry->key.secondary.i);
|
||||
break;
|
||||
case TYPE_STR:
|
||||
size += 1 + strlen(entry->key.secondary.s);
|
||||
put_asciz(bs, entry->key.secondary.s);
|
||||
break;
|
||||
}
|
||||
switch (valuetypes[entry->key.primary]) {
|
||||
case TYPE_INT:
|
||||
size += 4;
|
||||
put_uint32(bs, entry->value.u.intval);
|
||||
break;
|
||||
case TYPE_STR:
|
||||
size += 1 + strlen(entry->value.u.stringval);
|
||||
put_asciz(bs, entry->value.u.stringval);
|
||||
break;
|
||||
case TYPE_FILENAME:
|
||||
size += filename_serialise(entry->value.u.fileval, NULL);
|
||||
filename_serialise(bs, entry->value.u.fileval);
|
||||
break;
|
||||
case TYPE_FONT:
|
||||
size += fontspec_serialise(entry->value.u.fontval, NULL);
|
||||
fontspec_serialise(bs, entry->value.u.fontval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size += 4; /* terminator value */
|
||||
|
||||
return size;
|
||||
put_uint32(bs, 0xFFFFFFFFU);
|
||||
}
|
||||
|
||||
void conf_serialise(Conf *conf, void *vdata)
|
||||
int conf_deserialise(Conf *conf, BinarySource *src)
|
||||
{
|
||||
unsigned char *data = (unsigned char *)vdata;
|
||||
int i, len;
|
||||
struct conf_entry *entry;
|
||||
|
||||
for (i = 0; (entry = index234(conf->tree, i)) != NULL; i++) {
|
||||
PUT_32BIT_MSB_FIRST(data, entry->key.primary);
|
||||
data += 4;
|
||||
|
||||
switch (subkeytypes[entry->key.primary]) {
|
||||
case TYPE_INT:
|
||||
PUT_32BIT_MSB_FIRST(data, entry->key.secondary.i);
|
||||
data += 4;
|
||||
break;
|
||||
case TYPE_STR:
|
||||
len = strlen(entry->key.secondary.s);
|
||||
memcpy(data, entry->key.secondary.s, len);
|
||||
data += len;
|
||||
*data++ = 0;
|
||||
break;
|
||||
}
|
||||
switch (valuetypes[entry->key.primary]) {
|
||||
case TYPE_INT:
|
||||
PUT_32BIT_MSB_FIRST(data, entry->value.u.intval);
|
||||
data += 4;
|
||||
break;
|
||||
case TYPE_STR:
|
||||
len = strlen(entry->value.u.stringval);
|
||||
memcpy(data, entry->value.u.stringval, len);
|
||||
data += len;
|
||||
*data++ = 0;
|
||||
break;
|
||||
case TYPE_FILENAME:
|
||||
data += filename_serialise(entry->value.u.fileval, data);
|
||||
break;
|
||||
case TYPE_FONT:
|
||||
data += fontspec_serialise(entry->value.u.fontval, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PUT_32BIT_MSB_FIRST(data, 0xFFFFFFFFU);
|
||||
}
|
||||
|
||||
int conf_deserialise(Conf *conf, void *vdata, int maxsize)
|
||||
{
|
||||
unsigned char *data = (unsigned char *)vdata;
|
||||
unsigned char *start = data;
|
||||
struct conf_entry *entry;
|
||||
unsigned primary;
|
||||
int used;
|
||||
unsigned char *zero;
|
||||
|
||||
while (maxsize >= 4) {
|
||||
primary = GET_32BIT_MSB_FIRST(data);
|
||||
data += 4, maxsize -= 4;
|
||||
while (1) {
|
||||
primary = get_uint32(src);
|
||||
|
||||
if (get_err(src))
|
||||
return FALSE;
|
||||
if (primary == 0xFFFFFFFFU)
|
||||
return TRUE;
|
||||
if (primary >= N_CONFIG_OPTIONS)
|
||||
break;
|
||||
return FALSE;
|
||||
|
||||
entry = snew(struct conf_entry);
|
||||
entry->key.primary = primary;
|
||||
|
||||
switch (subkeytypes[entry->key.primary]) {
|
||||
case TYPE_INT:
|
||||
if (maxsize < 4) {
|
||||
sfree(entry);
|
||||
goto done;
|
||||
}
|
||||
entry->key.secondary.i = toint(GET_32BIT_MSB_FIRST(data));
|
||||
data += 4, maxsize -= 4;
|
||||
entry->key.secondary.i = toint(get_uint32(src));
|
||||
break;
|
||||
case TYPE_STR:
|
||||
zero = memchr(data, 0, maxsize);
|
||||
if (!zero) {
|
||||
sfree(entry);
|
||||
goto done;
|
||||
}
|
||||
entry->key.secondary.s = dupstr((char *)data);
|
||||
maxsize -= (zero + 1 - data);
|
||||
data = zero + 1;
|
||||
entry->key.secondary.s = dupstr(get_asciz(src));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (valuetypes[entry->key.primary]) {
|
||||
case TYPE_INT:
|
||||
if (maxsize < 4) {
|
||||
if (subkeytypes[entry->key.primary] == TYPE_STR)
|
||||
sfree(entry->key.secondary.s);
|
||||
sfree(entry);
|
||||
goto done;
|
||||
}
|
||||
entry->value.u.intval = toint(GET_32BIT_MSB_FIRST(data));
|
||||
data += 4, maxsize -= 4;
|
||||
entry->value.u.intval = toint(get_uint32(src));
|
||||
break;
|
||||
case TYPE_STR:
|
||||
zero = memchr(data, 0, maxsize);
|
||||
if (!zero) {
|
||||
if (subkeytypes[entry->key.primary] == TYPE_STR)
|
||||
sfree(entry->key.secondary.s);
|
||||
sfree(entry);
|
||||
goto done;
|
||||
}
|
||||
entry->value.u.stringval = dupstr((char *)data);
|
||||
maxsize -= (zero + 1 - data);
|
||||
data = zero + 1;
|
||||
entry->value.u.stringval = dupstr(get_asciz(src));
|
||||
break;
|
||||
case TYPE_FILENAME:
|
||||
entry->value.u.fileval =
|
||||
filename_deserialise(data, maxsize, &used);
|
||||
if (!entry->value.u.fileval) {
|
||||
if (subkeytypes[entry->key.primary] == TYPE_STR)
|
||||
sfree(entry->key.secondary.s);
|
||||
sfree(entry);
|
||||
goto done;
|
||||
}
|
||||
data += used;
|
||||
maxsize -= used;
|
||||
entry->value.u.fileval = filename_deserialise(src);
|
||||
break;
|
||||
case TYPE_FONT:
|
||||
entry->value.u.fontval =
|
||||
fontspec_deserialise(data, maxsize, &used);
|
||||
if (!entry->value.u.fontval) {
|
||||
if (subkeytypes[entry->key.primary] == TYPE_STR)
|
||||
sfree(entry->key.secondary.s);
|
||||
sfree(entry);
|
||||
goto done;
|
||||
}
|
||||
data += used;
|
||||
maxsize -= used;
|
||||
entry->value.u.fontval = fontspec_deserialise(src);
|
||||
break;
|
||||
}
|
||||
|
||||
if (get_err(src)) {
|
||||
free_entry(entry);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
conf_insert(conf, entry);
|
||||
}
|
||||
|
||||
done:
|
||||
return (int)(data - start);
|
||||
}
|
||||
|
||||
12
source/putty/cproxy.c
vendored
12
source/putty/cproxy.c
vendored
@@ -14,6 +14,7 @@
|
||||
#include "ssh.h" /* For MD5 support */
|
||||
#include "network.h"
|
||||
#include "proxy.h"
|
||||
#include "marshal.h"
|
||||
|
||||
static void hmacmd5_chap(const unsigned char *challenge, int challen,
|
||||
const char *passwd, unsigned char *response)
|
||||
@@ -36,13 +37,12 @@ static void hmacmd5_chap(const unsigned char *challenge, int challen,
|
||||
hmacmd5_free_context(hmacmd5_ctx);
|
||||
}
|
||||
|
||||
void proxy_socks5_offerencryptedauth(char *command, int *len)
|
||||
void proxy_socks5_offerencryptedauth(BinarySink *bs)
|
||||
{
|
||||
command[*len] = 0x03; /* CHAP */
|
||||
(*len)++;
|
||||
put_byte(bs, 0x03); /* CHAP */
|
||||
}
|
||||
|
||||
int proxy_socks5_handlechap (Proxy_Socket p)
|
||||
int proxy_socks5_handlechap (ProxySocket *p)
|
||||
{
|
||||
|
||||
/* CHAP authentication reply format:
|
||||
@@ -132,7 +132,7 @@ int proxy_socks5_handlechap (Proxy_Socket p)
|
||||
hmacmd5_chap(data, p->chap_current_datalen,
|
||||
conf_get_str(p->conf, CONF_proxy_password),
|
||||
&outbuf[4]);
|
||||
sk_write(p->sub_socket, (char *)outbuf, 20);
|
||||
sk_write(p->sub_socket, outbuf, 20);
|
||||
break;
|
||||
case 0x11:
|
||||
/* Chose a protocol */
|
||||
@@ -158,7 +158,7 @@ int proxy_socks5_handlechap (Proxy_Socket p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_socks5_selectchap(Proxy_Socket p)
|
||||
int proxy_socks5_selectchap(ProxySocket *p)
|
||||
{
|
||||
char *username = conf_get_str(p->conf, CONF_proxy_username);
|
||||
char *password = conf_get_str(p->conf, CONF_proxy_password);
|
||||
|
||||
80
source/putty/defs.h
vendored
Normal file
80
source/putty/defs.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* defs.h: initial definitions for PuTTY.
|
||||
*
|
||||
* The rule about this header file is that it can't depend on any
|
||||
* other header file in this code base. This is where we define
|
||||
* things, as much as we can, that other headers will want to refer
|
||||
* to, such as opaque structure types and their associated typedefs,
|
||||
* or macros that are used by other headers.
|
||||
*/
|
||||
|
||||
#ifndef PUTTY_DEFS_H
|
||||
#define PUTTY_DEFS_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
typedef struct conf_tag Conf;
|
||||
typedef struct backend_tag Backend;
|
||||
typedef struct terminal_tag Terminal;
|
||||
|
||||
typedef struct Filename Filename;
|
||||
typedef struct FontSpec FontSpec;
|
||||
|
||||
typedef struct bufchain_tag bufchain;
|
||||
|
||||
typedef struct strbuf strbuf;
|
||||
|
||||
struct RSAKey;
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uint32_t uint32;
|
||||
|
||||
typedef struct BinarySink BinarySink;
|
||||
typedef struct BinarySource BinarySource;
|
||||
|
||||
typedef struct SockAddr_tag *SockAddr;
|
||||
|
||||
typedef struct Socket_vtable Socket_vtable;
|
||||
typedef struct Plug_vtable Plug_vtable;
|
||||
|
||||
/* Note indirection: for historical reasons (it used to be closer to
|
||||
* the OS socket type), the type that most code uses for a socket is
|
||||
* 'Socket', not 'Socket *'. So an implementation of Socket or Plug
|
||||
* has a 'const Socket *' field for the vtable pointer, and the
|
||||
* 'Socket' type returned to client code is a pointer to _that_ in
|
||||
* turn. */
|
||||
typedef const Socket_vtable **Socket;
|
||||
typedef const Plug_vtable **Plug;
|
||||
|
||||
/*
|
||||
* A small structure wrapping up a (pointer, length) pair so that it
|
||||
* can be conveniently passed to or from a function.
|
||||
*/
|
||||
typedef struct ptrlen {
|
||||
const void *ptr;
|
||||
size_t len;
|
||||
} ptrlen;
|
||||
|
||||
typedef struct logblank_t logblank_t;
|
||||
|
||||
/* Do a compile-time type-check of 'to_check' (without evaluating it),
|
||||
* as a side effect of returning the value 'to_return'. Note that
|
||||
* although this macro double-*expands* to_return, it always
|
||||
* *evaluates* exactly one copy of it, so it's side-effect safe. */
|
||||
#define TYPECHECK(to_check, to_return) \
|
||||
(sizeof(to_check) ? (to_return) : (to_return))
|
||||
|
||||
/* Return a pointer to the object of structure type 'type' whose field
|
||||
* with name 'field' is pointed at by 'object'. */
|
||||
#define FROMFIELD(object, type, field) \
|
||||
TYPECHECK(object == &((type *)0)->field, \
|
||||
((type *)(((char *)(object)) - offsetof(type, field))))
|
||||
|
||||
#endif /* PUTTY_DEFS_H */
|
||||
64
source/putty/errsock.c
vendored
64
source/putty/errsock.c
vendored
@@ -10,37 +10,34 @@
|
||||
#include "putty.h"
|
||||
#include "network.h"
|
||||
|
||||
typedef struct Socket_error_tag *Error_Socket;
|
||||
|
||||
struct Socket_error_tag {
|
||||
const struct socket_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
|
||||
typedef struct {
|
||||
char *error;
|
||||
Plug plug;
|
||||
};
|
||||
|
||||
const Socket_vtable *sockvt;
|
||||
} ErrorSocket;
|
||||
|
||||
static Plug sk_error_plug(Socket s, Plug p)
|
||||
{
|
||||
Error_Socket ps = (Error_Socket) s;
|
||||
Plug ret = ps->plug;
|
||||
ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt);
|
||||
Plug ret = es->plug;
|
||||
if (p)
|
||||
ps->plug = p;
|
||||
es->plug = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sk_error_close(Socket s)
|
||||
{
|
||||
Error_Socket ps = (Error_Socket) s;
|
||||
ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt);
|
||||
|
||||
sfree(ps->error);
|
||||
sfree(ps);
|
||||
sfree(es->error);
|
||||
sfree(es);
|
||||
}
|
||||
|
||||
static const char *sk_error_socket_error(Socket s)
|
||||
{
|
||||
Error_Socket ps = (Error_Socket) s;
|
||||
return ps->error;
|
||||
ErrorSocket *es = FROMFIELD(s, ErrorSocket, sockvt);
|
||||
return es->error;
|
||||
}
|
||||
|
||||
static char *sk_error_peer_info(Socket s)
|
||||
@@ -48,26 +45,23 @@ static char *sk_error_peer_info(Socket s)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const Socket_vtable ErrorSocket_sockvt = {
|
||||
sk_error_plug,
|
||||
sk_error_close,
|
||||
NULL /* write */,
|
||||
NULL /* write_oob */,
|
||||
NULL /* write_eof */,
|
||||
NULL /* flush */,
|
||||
NULL /* set_frozen */,
|
||||
sk_error_socket_error,
|
||||
sk_error_peer_info,
|
||||
};
|
||||
|
||||
Socket new_error_socket(const char *errmsg, Plug plug)
|
||||
{
|
||||
static const struct socket_function_table socket_fn_table = {
|
||||
sk_error_plug,
|
||||
sk_error_close,
|
||||
NULL /* write */,
|
||||
NULL /* write_oob */,
|
||||
NULL /* write_eof */,
|
||||
NULL /* flush */,
|
||||
NULL /* set_frozen */,
|
||||
sk_error_socket_error,
|
||||
sk_error_peer_info,
|
||||
};
|
||||
|
||||
Error_Socket ret;
|
||||
|
||||
ret = snew(struct Socket_error_tag);
|
||||
ret->fn = &socket_fn_table;
|
||||
ret->plug = plug;
|
||||
ret->error = dupstr(errmsg);
|
||||
|
||||
return (Socket) ret;
|
||||
ErrorSocket *es = snew(ErrorSocket);
|
||||
es->sockvt = &ErrorSocket_sockvt;
|
||||
es->plug = plug;
|
||||
es->error = dupstr(errmsg);
|
||||
return &es->sockvt;
|
||||
}
|
||||
|
||||
1581
source/putty/import.c
vendored
1581
source/putty/import.c
vendored
File diff suppressed because it is too large
Load Diff
5
source/putty/int64.h
vendored
5
source/putty/int64.h
vendored
@@ -5,6 +5,8 @@
|
||||
#ifndef PUTTY_INT64_H
|
||||
#define PUTTY_INT64_H
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned long hi, lo;
|
||||
} uint64;
|
||||
@@ -21,4 +23,7 @@ uint64 uint64_shift_right(uint64 x, int shift);
|
||||
uint64 uint64_shift_left(uint64 x, int shift);
|
||||
uint64 uint64_from_decimal(char *str);
|
||||
|
||||
void BinarySink_put_uint64(BinarySink *, uint64);
|
||||
uint64 BinarySource_get_uint64(BinarySource *);
|
||||
|
||||
#endif
|
||||
|
||||
7
source/putty/logging.c
vendored
7
source/putty/logging.c
vendored
@@ -164,7 +164,6 @@ void logfopen(void *handle)
|
||||
{
|
||||
struct LogContext *ctx = (struct LogContext *)handle;
|
||||
struct tm tm;
|
||||
FILE *fp;
|
||||
int mode;
|
||||
|
||||
/* Prevent repeat calls */
|
||||
@@ -184,10 +183,8 @@ void logfopen(void *handle)
|
||||
conf_get_str(ctx->conf, CONF_host),
|
||||
conf_get_int(ctx->conf, CONF_port), &tm);
|
||||
|
||||
fp = f_open(ctx->currlogfilename, "r", FALSE); /* file already present? */
|
||||
if (fp) {
|
||||
if (open_for_write_would_lose_data(ctx->currlogfilename)) {
|
||||
int logxfovr = conf_get_int(ctx->conf, CONF_logxfovr);
|
||||
fclose(fp);
|
||||
if (logxfovr != LGXF_ASK) {
|
||||
mode = ((logxfovr == LGXF_OVR) ? 2 : 1);
|
||||
} else
|
||||
@@ -351,7 +348,7 @@ void log_packet(void *handle, int direction, int type,
|
||||
}
|
||||
dumpdata[10+2+3*(p%16)] = smalldata[0];
|
||||
dumpdata[10+2+3*(p%16)+1] = smalldata[1];
|
||||
dumpdata[10+1+3*16+2+(p%16)] = (isprint(c) ? c : '.');
|
||||
dumpdata[10+1+3*16+2+(p%16)] = (c >= 0x20 && c < 0x7F ? c : '.');
|
||||
output_pos = (p%16) + 1;
|
||||
}
|
||||
|
||||
|
||||
236
source/putty/marshal.c
vendored
Normal file
236
source/putty/marshal.c
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "marshal.h"
|
||||
#include "misc.h"
|
||||
#include "int64.h"
|
||||
|
||||
void BinarySink_put_data(BinarySink *bs, const void *data, size_t len)
|
||||
{
|
||||
bs->write(bs, data, len);
|
||||
}
|
||||
|
||||
void BinarySink_put_padding(BinarySink *bs, size_t len, unsigned char padbyte)
|
||||
{
|
||||
char buf[16];
|
||||
memset(buf, padbyte, sizeof(buf));
|
||||
while (len > 0) {
|
||||
size_t thislen = len < sizeof(buf) ? len : sizeof(buf);
|
||||
bs->write(bs, buf, thislen);
|
||||
len -= thislen;
|
||||
}
|
||||
}
|
||||
|
||||
void BinarySink_put_byte(BinarySink *bs, unsigned char val)
|
||||
{
|
||||
bs->write(bs, &val, 1);
|
||||
}
|
||||
|
||||
void BinarySink_put_bool(BinarySink *bs, int val)
|
||||
{
|
||||
unsigned char cval = val ? 1 : 0;
|
||||
bs->write(bs, &cval, 1);
|
||||
}
|
||||
|
||||
void BinarySink_put_uint16(BinarySink *bs, unsigned long val)
|
||||
{
|
||||
unsigned char data[2];
|
||||
PUT_16BIT_MSB_FIRST(data, val);
|
||||
bs->write(bs, data, sizeof(data));
|
||||
}
|
||||
|
||||
void BinarySink_put_uint32(BinarySink *bs, unsigned long val)
|
||||
{
|
||||
unsigned char data[4];
|
||||
PUT_32BIT_MSB_FIRST(data, val);
|
||||
bs->write(bs, data, sizeof(data));
|
||||
}
|
||||
|
||||
void BinarySink_put_uint64(BinarySink *bs, uint64 val)
|
||||
{
|
||||
BinarySink_put_uint32(bs, val.hi);
|
||||
BinarySink_put_uint32(bs, val.lo);
|
||||
}
|
||||
|
||||
void BinarySink_put_string(BinarySink *bs, const void *data, size_t len)
|
||||
{
|
||||
/* Check that the string length fits in a uint32, without doing a
|
||||
* potentially implementation-defined shift of more than 31 bits */
|
||||
assert((len >> 31) < 2);
|
||||
|
||||
BinarySink_put_uint32(bs, len);
|
||||
bs->write(bs, data, len);
|
||||
}
|
||||
|
||||
void BinarySink_put_stringpl(BinarySink *bs, ptrlen pl)
|
||||
{
|
||||
BinarySink_put_string(bs, pl.ptr, pl.len);
|
||||
}
|
||||
|
||||
void BinarySink_put_stringz(BinarySink *bs, const char *str)
|
||||
{
|
||||
BinarySink_put_string(bs, str, strlen(str));
|
||||
}
|
||||
|
||||
void BinarySink_put_stringsb(BinarySink *bs, struct strbuf *buf)
|
||||
{
|
||||
BinarySink_put_string(bs, buf->s, buf->len);
|
||||
strbuf_free(buf);
|
||||
}
|
||||
|
||||
void BinarySink_put_asciz(BinarySink *bs, const char *str)
|
||||
{
|
||||
bs->write(bs, str, strlen(str) + 1);
|
||||
}
|
||||
|
||||
int BinarySink_put_pstring(BinarySink *bs, const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
if (len > 255)
|
||||
return FALSE; /* can't write a Pascal-style string this long */
|
||||
BinarySink_put_byte(bs, len);
|
||||
bs->write(bs, str, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int BinarySource_data_avail(BinarySource *src, size_t wanted)
|
||||
{
|
||||
if (src->err)
|
||||
return FALSE;
|
||||
|
||||
if (wanted <= src->len - src->pos)
|
||||
return TRUE;
|
||||
|
||||
src->err = BSE_OUT_OF_DATA;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define avail(wanted) BinarySource_data_avail(src, wanted)
|
||||
#define advance(dist) (src->pos += dist)
|
||||
#define here ((const void *)((const unsigned char *)src->data + src->pos))
|
||||
#define consume(dist) \
|
||||
((const void *)((const unsigned char *)src->data + \
|
||||
((src->pos += dist) - dist)))
|
||||
|
||||
ptrlen BinarySource_get_data(BinarySource *src, size_t wanted)
|
||||
{
|
||||
if (!avail(wanted))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
return make_ptrlen(consume(wanted), wanted);
|
||||
}
|
||||
|
||||
unsigned char BinarySource_get_byte(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
|
||||
if (!avail(1))
|
||||
return 0;
|
||||
|
||||
ucp = consume(1);
|
||||
return *ucp;
|
||||
}
|
||||
|
||||
int BinarySource_get_bool(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
|
||||
if (!avail(1))
|
||||
return 0;
|
||||
|
||||
ucp = consume(1);
|
||||
return *ucp != 0;
|
||||
}
|
||||
|
||||
unsigned BinarySource_get_uint16(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
|
||||
if (!avail(2))
|
||||
return 0;
|
||||
|
||||
ucp = consume(2);
|
||||
return GET_16BIT_MSB_FIRST(ucp);
|
||||
}
|
||||
|
||||
unsigned long BinarySource_get_uint32(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
|
||||
if (!avail(4))
|
||||
return 0;
|
||||
|
||||
ucp = consume(4);
|
||||
return GET_32BIT_MSB_FIRST(ucp);
|
||||
}
|
||||
|
||||
uint64 BinarySource_get_uint64(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
uint64 toret;
|
||||
|
||||
if (!avail(8)) {
|
||||
toret.hi = toret.lo = 0;
|
||||
return toret;
|
||||
}
|
||||
|
||||
ucp = consume(8);
|
||||
toret.hi = GET_32BIT_MSB_FIRST(ucp);
|
||||
toret.lo = GET_32BIT_MSB_FIRST(ucp + 4);
|
||||
return toret;
|
||||
}
|
||||
|
||||
ptrlen BinarySource_get_string(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
size_t len;
|
||||
|
||||
if (!avail(4))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
ucp = consume(4);
|
||||
len = GET_32BIT_MSB_FIRST(ucp);
|
||||
|
||||
if (!avail(len))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
return make_ptrlen(consume(len), len);
|
||||
}
|
||||
|
||||
const char *BinarySource_get_asciz(BinarySource *src)
|
||||
{
|
||||
const char *start, *end;
|
||||
|
||||
if (src->err)
|
||||
return "";
|
||||
|
||||
start = here;
|
||||
end = memchr(start, '\0', src->len - src->pos);
|
||||
if (!end) {
|
||||
src->err = BSE_OUT_OF_DATA;
|
||||
return "";
|
||||
}
|
||||
|
||||
advance(end + 1 - start);
|
||||
return start;
|
||||
}
|
||||
|
||||
ptrlen BinarySource_get_pstring(BinarySource *src)
|
||||
{
|
||||
const unsigned char *ucp;
|
||||
size_t len;
|
||||
|
||||
if (!avail(1))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
ucp = consume(1);
|
||||
len = *ucp;
|
||||
|
||||
if (!avail(len))
|
||||
return make_ptrlen("", 0);
|
||||
|
||||
return make_ptrlen(consume(len), len);
|
||||
}
|
||||
273
source/putty/marshal.h
vendored
Normal file
273
source/putty/marshal.h
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
#ifndef PUTTY_MARSHAL_H
|
||||
#define PUTTY_MARSHAL_H
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
/*
|
||||
* A sort of 'abstract base class' or 'interface' or 'trait' which is
|
||||
* the common feature of all types that want to accept data formatted
|
||||
* using the SSH binary conventions of uint32, string, mpint etc.
|
||||
*/
|
||||
struct BinarySink {
|
||||
void (*write)(BinarySink *sink, const void *data, size_t len);
|
||||
BinarySink *binarysink_;
|
||||
};
|
||||
|
||||
/*
|
||||
* To define a structure type as a valid target for binary formatted
|
||||
* data, put 'BinarySink_IMPLEMENTATION' in its declaration, and when
|
||||
* an instance is set up, use 'BinarySink_INIT' to initialise the
|
||||
* 'base class' state, providing a function pointer to be the
|
||||
* implementation of the write() call above.
|
||||
*/
|
||||
#define BinarySink_IMPLEMENTATION BinarySink binarysink_[1]
|
||||
#define BinarySink_INIT(obj, writefn) \
|
||||
((obj)->binarysink_->write = (writefn), \
|
||||
(obj)->binarysink_->binarysink_ = (obj)->binarysink_)
|
||||
|
||||
/*
|
||||
* The implementing type's write function will want to downcast its
|
||||
* 'BinarySink *' parameter back to the more specific type. Also,
|
||||
* sometimes you'll want to upcast a pointer to a particular
|
||||
* implementing type into an abstract 'BinarySink *' to pass to
|
||||
* generic subroutines not defined in this file. These macros do that
|
||||
* job.
|
||||
*
|
||||
* Importantly, BinarySink_UPCAST can also be applied to a BinarySink
|
||||
* * itself (and leaves it unchanged). That's achieved by a small
|
||||
* piece of C trickery: implementing structures and the BinarySink
|
||||
* structure itself both contain a field called binarysink_, but in
|
||||
* implementing objects it's a BinarySink[1] whereas in the abstract
|
||||
* type it's a 'BinarySink *' pointing back to the same structure,
|
||||
* meaning that you can say 'foo->binarysink_' in either case and get
|
||||
* a pointer type by different methods.
|
||||
*/
|
||||
#define BinarySink_DOWNCAST(object, type) \
|
||||
TYPECHECK((object) == ((type *)0)->binarysink_, \
|
||||
((type *)(((char *)(object)) - offsetof(type, binarysink_))))
|
||||
#define BinarySink_UPCAST(object) \
|
||||
TYPECHECK((object)->binarysink_ == (BinarySink *)0, \
|
||||
(object)->binarysink_)
|
||||
|
||||
/*
|
||||
* If you structure-copy an object that's implementing BinarySink,
|
||||
* then that tricky self-pointer in its trait subobject will point to
|
||||
* the wrong place. You could call BinarySink_INIT again, but this
|
||||
* macro is terser and does all that's needed to fix up the copied
|
||||
* object.
|
||||
*/
|
||||
#define BinarySink_COPIED(obj) \
|
||||
((obj)->binarysink_->binarysink_ = (obj)->binarysink_)
|
||||
|
||||
/*
|
||||
* The put_* macros are the main client to this system. Any structure
|
||||
* which implements the BinarySink 'trait' is valid for use as the
|
||||
* first parameter of any of these put_* macros.
|
||||
*/
|
||||
|
||||
/* Basic big-endian integer types. uint64 is the structure type
|
||||
* defined in int64.h, not the C99 built-in type. */
|
||||
#define put_byte(bs, val) \
|
||||
BinarySink_put_byte(BinarySink_UPCAST(bs), val)
|
||||
#define put_uint16(bs, val) \
|
||||
BinarySink_put_uint16(BinarySink_UPCAST(bs), val)
|
||||
#define put_uint32(bs, val) \
|
||||
BinarySink_put_uint32(BinarySink_UPCAST(bs), val)
|
||||
#define put_uint64(bs, val) \
|
||||
BinarySink_put_uint64(BinarySink_UPCAST(bs), val)
|
||||
|
||||
/* SSH booleans, encoded as a single byte storing either 0 or 1. */
|
||||
#define put_bool(bs, val) \
|
||||
BinarySink_put_bool(BinarySink_UPCAST(bs), val)
|
||||
|
||||
/* SSH strings, with a leading uint32 length field. 'stringz' is a
|
||||
* convenience function that takes an ordinary C zero-terminated
|
||||
* string as input. 'stringsb' takes a strbuf * as input, and
|
||||
* finalises it as a side effect (handy for multi-level marshalling in
|
||||
* which you use these same functions to format an inner blob of data
|
||||
* that then gets wrapped into a string container in an outer one). */
|
||||
#define put_string(bs, val, len) \
|
||||
BinarySink_put_string(BinarySink_UPCAST(bs),val,len)
|
||||
#define put_stringpl(bs, ptrlen) \
|
||||
BinarySink_put_stringpl(BinarySink_UPCAST(bs),ptrlen)
|
||||
#define put_stringz(bs, val) \
|
||||
BinarySink_put_stringz(BinarySink_UPCAST(bs), val)
|
||||
#define put_stringsb(bs, val) \
|
||||
BinarySink_put_stringsb(BinarySink_UPCAST(bs), val)
|
||||
|
||||
/* Other string outputs: 'asciz' emits the string data directly into
|
||||
* the output including the terminating \0, and 'pstring' emits the
|
||||
* string in Pascal style with a leading _one_-byte length field.
|
||||
* pstring can fail if the string is too long. */
|
||||
#define put_asciz(bs, val) \
|
||||
BinarySink_put_asciz(BinarySink_UPCAST(bs), val)
|
||||
#define put_pstring(bs, val) \
|
||||
BinarySink_put_pstring(BinarySink_UPCAST(bs), val)
|
||||
|
||||
/* Multiprecision integers, in both the SSH-1 and SSH-2 formats. */
|
||||
#define put_mp_ssh1(bs, val) \
|
||||
BinarySink_put_mp_ssh1(BinarySink_UPCAST(bs), val)
|
||||
#define put_mp_ssh2(bs, val) \
|
||||
BinarySink_put_mp_ssh2(BinarySink_UPCAST(bs), val)
|
||||
|
||||
/* Padding with a specified byte. */
|
||||
#define put_padding(bs, len, padbyte) \
|
||||
BinarySink_put_padding(BinarySink_UPCAST(bs), len, padbyte)
|
||||
|
||||
/* Fallback: just emit raw data bytes, using a syntax that matches the
|
||||
* rest of these macros. */
|
||||
#define put_data(bs, val, len) \
|
||||
BinarySink_put_data(BinarySink_UPCAST(bs), val, len)
|
||||
|
||||
/*
|
||||
* The underlying real C functions that implement most of those
|
||||
* macros. Generally you won't want to call these directly, because
|
||||
* they have such cumbersome names; you call the wrapper macros above
|
||||
* instead.
|
||||
*
|
||||
* A few functions whose wrapper macros are defined above are actually
|
||||
* declared in other headers, so as to guarantee that the
|
||||
* declaration(s) of their other parameter type(s) are in scope.
|
||||
*/
|
||||
void BinarySink_put_data(BinarySink *, const void *data, size_t len);
|
||||
void BinarySink_put_padding(BinarySink *, size_t len, unsigned char padbyte);
|
||||
void BinarySink_put_byte(BinarySink *, unsigned char);
|
||||
void BinarySink_put_bool(BinarySink *, int);
|
||||
void BinarySink_put_uint16(BinarySink *, unsigned long);
|
||||
void BinarySink_put_uint32(BinarySink *, unsigned long);
|
||||
void BinarySink_put_string(BinarySink *, const void *data, size_t len);
|
||||
void BinarySink_put_stringpl(BinarySink *, ptrlen);
|
||||
void BinarySink_put_stringz(BinarySink *, const char *str);
|
||||
struct strbuf;
|
||||
void BinarySink_put_stringsb(BinarySink *, struct strbuf *);
|
||||
void BinarySink_put_asciz(BinarySink *, const char *str);
|
||||
int BinarySink_put_pstring(BinarySink *, const char *str);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* A complementary trait structure for _un_-marshalling.
|
||||
*
|
||||
* This structure contains client-visible data fields rather than
|
||||
* methods, because that seemed more useful than leaving it totally
|
||||
* opaque. But it's still got the self-pointer system that will allow
|
||||
* the set of get_* macros to target one of these itself or any other
|
||||
* type that 'derives' from it. So, for example, an SSH packet
|
||||
* structure can act as a BinarySource while also having additional
|
||||
* fields like the packet type.
|
||||
*/
|
||||
typedef enum BinarySourceError {
|
||||
BSE_NO_ERROR,
|
||||
BSE_OUT_OF_DATA,
|
||||
BSE_INVALID
|
||||
} BinarySourceError;
|
||||
struct BinarySource {
|
||||
/*
|
||||
* (data, len) is the data block being decoded. pos is the current
|
||||
* position within the block.
|
||||
*/
|
||||
const void *data;
|
||||
size_t pos, len;
|
||||
|
||||
/*
|
||||
* 'err' indicates whether a decoding error has happened at any
|
||||
* point. Once this has been set to something other than
|
||||
* BSE_NO_ERROR, it shouldn't be changed by any unmarshalling
|
||||
* function. So you can safely do a long sequence of get_foo()
|
||||
* operations and then test err just once at the end, rather than
|
||||
* having to conditionalise every single get.
|
||||
*
|
||||
* The unmarshalling functions should always return some value,
|
||||
* even if a decoding error occurs. Generally on error they'll
|
||||
* return zero (if numeric) or the empty string (if string-based),
|
||||
* or some other appropriate default value for more complicated
|
||||
* types.
|
||||
*
|
||||
* If the usual return value is dynamically allocated (e.g. a
|
||||
* Bignum, or a normal C 'char *' string), then the error value is
|
||||
* also dynamic in the same way. So you have to free exactly the
|
||||
* same set of things whether or not there was a decoding error,
|
||||
* which simplifies exit paths - for example, you could call a big
|
||||
* pile of get_foo functions, then put the actual handling of the
|
||||
* results under 'if (!get_err(src))', and then free everything
|
||||
* outside that if.
|
||||
*/
|
||||
BinarySourceError err;
|
||||
|
||||
/*
|
||||
* Self-pointer for the implicit derivation trick, same as
|
||||
* BinarySink above.
|
||||
*/
|
||||
BinarySource *binarysource_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Implementation macros, similar to BinarySink.
|
||||
*/
|
||||
#define BinarySource_IMPLEMENTATION BinarySource binarysource_[1]
|
||||
#define BinarySource_INIT__(obj, data_, len_) \
|
||||
((obj)->data = (data_), \
|
||||
(obj)->len = (len_), \
|
||||
(obj)->pos = 0, \
|
||||
(obj)->err = BSE_NO_ERROR, \
|
||||
(obj)->binarysource_ = (obj))
|
||||
#define BinarySource_BARE_INIT(obj, data_, len_) \
|
||||
TYPECHECK(&(obj)->binarysource_ == (BinarySource **)0, \
|
||||
BinarySource_INIT__(obj, data_, len_))
|
||||
#define BinarySource_INIT(obj, data_, len_) \
|
||||
TYPECHECK(&(obj)->binarysource_ == (BinarySource (*)[1])0, \
|
||||
BinarySource_INIT__(BinarySource_UPCAST(obj), data_, len_))
|
||||
#define BinarySource_DOWNCAST(object, type) \
|
||||
TYPECHECK((object) == ((type *)0)->binarysource_, \
|
||||
((type *)(((char *)(object)) - offsetof(type, binarysource_))))
|
||||
#define BinarySource_UPCAST(object) \
|
||||
TYPECHECK((object)->binarysource_ == (BinarySource *)0, \
|
||||
(object)->binarysource_)
|
||||
#define BinarySource_COPIED(obj) \
|
||||
((obj)->binarysource_->binarysource_ = (obj)->binarysource_)
|
||||
|
||||
#define get_data(src, len) \
|
||||
BinarySource_get_data(BinarySource_UPCAST(src), len)
|
||||
#define get_byte(src) \
|
||||
BinarySource_get_byte(BinarySource_UPCAST(src))
|
||||
#define get_bool(src) \
|
||||
BinarySource_get_bool(BinarySource_UPCAST(src))
|
||||
#define get_uint16(src) \
|
||||
BinarySource_get_uint16(BinarySource_UPCAST(src))
|
||||
#define get_uint32(src) \
|
||||
BinarySource_get_uint32(BinarySource_UPCAST(src))
|
||||
#define get_uint64(src) \
|
||||
BinarySource_get_uint64(BinarySource_UPCAST(src))
|
||||
#define get_string(src) \
|
||||
BinarySource_get_string(BinarySource_UPCAST(src))
|
||||
#define get_asciz(src) \
|
||||
BinarySource_get_asciz(BinarySource_UPCAST(src))
|
||||
#define get_pstring(src) \
|
||||
BinarySource_get_pstring(BinarySource_UPCAST(src))
|
||||
#define get_mp_ssh1(src) \
|
||||
BinarySource_get_mp_ssh1(BinarySource_UPCAST(src))
|
||||
#define get_mp_ssh2(src) \
|
||||
BinarySource_get_mp_ssh2(BinarySource_UPCAST(src))
|
||||
#define get_rsa_ssh1_pub(src, rsa, order) \
|
||||
BinarySource_get_rsa_ssh1_pub(BinarySource_UPCAST(src), rsa, order)
|
||||
#define get_rsa_ssh1_priv(src, rsa) \
|
||||
BinarySource_get_rsa_ssh1_priv(BinarySource_UPCAST(src), rsa)
|
||||
|
||||
#define get_err(src) (BinarySource_UPCAST(src)->err)
|
||||
#define get_avail(src) (BinarySource_UPCAST(src)->len - \
|
||||
BinarySource_UPCAST(src)->pos)
|
||||
#define get_ptr(src) \
|
||||
((const void *)( \
|
||||
(const unsigned char *)(BinarySource_UPCAST(src)->data) + \
|
||||
BinarySource_UPCAST(src)->pos))
|
||||
|
||||
ptrlen BinarySource_get_data(BinarySource *, size_t);
|
||||
unsigned char BinarySource_get_byte(BinarySource *);
|
||||
int BinarySource_get_bool(BinarySource *);
|
||||
unsigned BinarySource_get_uint16(BinarySource *);
|
||||
unsigned long BinarySource_get_uint32(BinarySource *);
|
||||
ptrlen BinarySource_get_string(BinarySource *);
|
||||
const char *BinarySource_get_asciz(BinarySource *);
|
||||
ptrlen BinarySource_get_pstring(BinarySource *);
|
||||
|
||||
#endif /* PUTTY_MARSHAL_H */
|
||||
150
source/putty/misc.c
vendored
150
source/putty/misc.c
vendored
@@ -360,6 +360,16 @@ int toint(unsigned u)
|
||||
return INT_MIN; /* fallback; should never occur on binary machines */
|
||||
}
|
||||
|
||||
int string_length_for_printf(size_t s)
|
||||
{
|
||||
/* Truncate absurdly long strings (should one show up) to fit
|
||||
* within a positive 'int', which is what the "%.*s" format will
|
||||
* expect. */
|
||||
if (s > INT_MAX)
|
||||
return INT_MAX;
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do an sprintf(), but into a custom-allocated buffer.
|
||||
*
|
||||
@@ -466,47 +476,90 @@ char *dupprintf(const char *fmt, ...)
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct strbuf {
|
||||
char *s;
|
||||
int len, size;
|
||||
struct strbuf_impl {
|
||||
int size;
|
||||
struct strbuf visible;
|
||||
};
|
||||
|
||||
#define STRBUF_SET_PTR(buf, ptr) \
|
||||
((buf)->visible.s = (ptr), \
|
||||
(buf)->visible.u = (unsigned char *)(buf)->visible.s)
|
||||
|
||||
void *strbuf_append(strbuf *buf_o, size_t len)
|
||||
{
|
||||
struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible);
|
||||
char *toret;
|
||||
if (buf->size < buf->visible.len + len + 1) {
|
||||
buf->size = (buf->visible.len + len + 1) * 5 / 4 + 512;
|
||||
STRBUF_SET_PTR(buf, sresize(buf->visible.s, buf->size, char));
|
||||
}
|
||||
toret = buf->visible.s + buf->visible.len;
|
||||
buf->visible.len += len;
|
||||
buf->visible.s[buf->visible.len] = '\0';
|
||||
return toret;
|
||||
}
|
||||
|
||||
static void strbuf_BinarySink_write(
|
||||
BinarySink *bs, const void *data, size_t len)
|
||||
{
|
||||
strbuf *buf_o = BinarySink_DOWNCAST(bs, strbuf);
|
||||
memcpy(strbuf_append(buf_o, len), data, len);
|
||||
}
|
||||
|
||||
strbuf *strbuf_new(void)
|
||||
{
|
||||
strbuf *buf = snew(strbuf);
|
||||
buf->len = 0;
|
||||
struct strbuf_impl *buf = snew(struct strbuf_impl);
|
||||
BinarySink_INIT(&buf->visible, strbuf_BinarySink_write);
|
||||
buf->visible.len = 0;
|
||||
buf->size = 512;
|
||||
buf->s = snewn(buf->size, char);
|
||||
*buf->s = '\0';
|
||||
return buf;
|
||||
STRBUF_SET_PTR(buf, snewn(buf->size, char));
|
||||
*buf->visible.s = '\0';
|
||||
return &buf->visible;
|
||||
}
|
||||
void strbuf_free(strbuf *buf)
|
||||
void strbuf_free(strbuf *buf_o)
|
||||
{
|
||||
sfree(buf->s);
|
||||
struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible);
|
||||
if (buf->visible.s) {
|
||||
smemclr(buf->visible.s, buf->size);
|
||||
sfree(buf->visible.s);
|
||||
}
|
||||
sfree(buf);
|
||||
}
|
||||
char *strbuf_str(strbuf *buf)
|
||||
char *strbuf_to_str(strbuf *buf_o)
|
||||
{
|
||||
return buf->s;
|
||||
}
|
||||
char *strbuf_to_str(strbuf *buf)
|
||||
{
|
||||
char *ret = buf->s;
|
||||
struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible);
|
||||
char *ret = buf->visible.s;
|
||||
sfree(buf);
|
||||
return ret;
|
||||
}
|
||||
void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap)
|
||||
void strbuf_catfv(strbuf *buf_o, const char *fmt, va_list ap)
|
||||
{
|
||||
buf->s = dupvprintf_inner(buf->s, buf->len, &buf->size, fmt, ap);
|
||||
buf->len += strlen(buf->s + buf->len);
|
||||
struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible);
|
||||
STRBUF_SET_PTR(buf, dupvprintf_inner(buf->visible.s, buf->visible.len,
|
||||
&buf->size, fmt, ap));
|
||||
buf->visible.len += strlen(buf->visible.s + buf->visible.len);
|
||||
}
|
||||
void strbuf_catf(strbuf *buf, const char *fmt, ...)
|
||||
void strbuf_catf(strbuf *buf_o, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
strbuf_catfv(buf, fmt, ap);
|
||||
strbuf_catfv(buf_o, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
strbuf *strbuf_new_for_agent_query(void)
|
||||
{
|
||||
strbuf *buf = strbuf_new();
|
||||
put_uint32(buf, 0); /* reserve space for length field */
|
||||
return buf;
|
||||
}
|
||||
void strbuf_finalise_agent_query(strbuf *buf_o)
|
||||
{
|
||||
struct strbuf_impl *buf = FROMFIELD(buf_o, struct strbuf_impl, visible);
|
||||
assert(buf->visible.len >= 5);
|
||||
PUT_32BIT_MSB_FIRST(buf->visible.u, buf->visible.len - 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an entire line of text from a file. Return a buffer
|
||||
* malloced to be as big as necessary (caller must free).
|
||||
@@ -754,6 +807,22 @@ void bufchain_fetch(bufchain *ch, void *data, int len)
|
||||
}
|
||||
}
|
||||
|
||||
void bufchain_fetch_consume(bufchain *ch, void *data, int len)
|
||||
{
|
||||
bufchain_fetch(ch, data, len);
|
||||
bufchain_consume(ch, len);
|
||||
}
|
||||
|
||||
int bufchain_try_fetch_consume(bufchain *ch, void *data, int len)
|
||||
{
|
||||
if (ch->buffersize >= len) {
|
||||
bufchain_fetch_consume(ch, data, len);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* My own versions of malloc, realloc and free. Because I want
|
||||
* malloc and realloc to bomb out and exit the program if they run
|
||||
@@ -1115,37 +1184,26 @@ int smemeq(const void *av, const void *bv, size_t len)
|
||||
return (0x100 - val) >> 8;
|
||||
}
|
||||
|
||||
int match_ssh_id(int stringlen, const void *string, const char *id)
|
||||
ptrlen make_ptrlen(const void *ptr, size_t len)
|
||||
{
|
||||
int idlen = strlen(id);
|
||||
return (idlen == stringlen && !memcmp(string, id, idlen));
|
||||
ptrlen pl;
|
||||
pl.ptr = ptr;
|
||||
pl.len = len;
|
||||
return pl;
|
||||
}
|
||||
|
||||
void *get_ssh_string(int *datalen, const void **data, int *stringlen)
|
||||
int ptrlen_eq_string(ptrlen pl, const char *str)
|
||||
{
|
||||
void *ret;
|
||||
unsigned int len;
|
||||
|
||||
if (*datalen < 4)
|
||||
return NULL;
|
||||
len = GET_32BIT_MSB_FIRST((const unsigned char *)*data);
|
||||
if (*datalen - 4 < len)
|
||||
return NULL;
|
||||
ret = (void *)((const char *)*data + 4);
|
||||
*datalen -= len + 4;
|
||||
*data = (const char *)*data + len + 4;
|
||||
*stringlen = len;
|
||||
return ret;
|
||||
size_t len = strlen(str);
|
||||
return (pl.len == len && !memcmp(pl.ptr, str, len));
|
||||
}
|
||||
|
||||
int get_ssh_uint32(int *datalen, const void **data, unsigned *ret)
|
||||
char *mkstr(ptrlen pl)
|
||||
{
|
||||
if (*datalen < 4)
|
||||
return FALSE;
|
||||
*ret = GET_32BIT_MSB_FIRST((const unsigned char *)*data);
|
||||
*datalen -= 4;
|
||||
*data = (const char *)*data + 4;
|
||||
return TRUE;
|
||||
char *p = snewn(pl.len + 1, char);
|
||||
memcpy(p, pl.ptr, pl.len);
|
||||
p[pl.len] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
int strstartswith(const char *s, const char *t)
|
||||
@@ -1186,6 +1244,8 @@ char *buildinfo(const char *newline)
|
||||
strbuf_catf(buf, "Visual Studio", newline);
|
||||
#if _MSC_VER == 1900
|
||||
strbuf_catf(buf, " 2015 / MSVC++ 14.0");
|
||||
#elif _MSC_VER == 1912
|
||||
strbuf_catf(buf, " 2017 / MSVC++ 14.12");
|
||||
#elif _MSC_VER == 1800
|
||||
strbuf_catf(buf, " 2013 / MSVC++ 12.0");
|
||||
#elif _MSC_VER == 1700
|
||||
|
||||
57
source/putty/misc.h
vendored
57
source/putty/misc.h
vendored
@@ -5,22 +5,14 @@
|
||||
#ifndef PUTTY_MISC_H
|
||||
#define PUTTY_MISC_H
|
||||
|
||||
#include "defs.h"
|
||||
#include "puttymem.h"
|
||||
#include "marshal.h"
|
||||
|
||||
#include <stdio.h> /* for FILE * */
|
||||
#include <stdarg.h> /* for va_list */
|
||||
#include <time.h> /* for struct tm */
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
typedef struct Filename Filename;
|
||||
typedef struct FontSpec FontSpec;
|
||||
|
||||
unsigned long parse_blocksize(const char *bs);
|
||||
char ctrlparse(char *s, char **next);
|
||||
|
||||
@@ -38,14 +30,24 @@ char *dupprintf(const char *fmt, ...)
|
||||
;
|
||||
char *dupvprintf(const char *fmt, va_list ap);
|
||||
void burnstr(char *string);
|
||||
typedef struct strbuf strbuf;
|
||||
|
||||
struct strbuf {
|
||||
char *s;
|
||||
unsigned char *u;
|
||||
int len;
|
||||
BinarySink_IMPLEMENTATION;
|
||||
/* (also there's a surrounding implementation struct in misc.c) */
|
||||
};
|
||||
strbuf *strbuf_new(void);
|
||||
void strbuf_free(strbuf *buf);
|
||||
char *strbuf_str(strbuf *buf); /* does not free buf */
|
||||
void *strbuf_append(strbuf *buf, size_t len);
|
||||
char *strbuf_to_str(strbuf *buf); /* does free buf, but you must free result */
|
||||
void strbuf_catf(strbuf *buf, const char *fmt, ...);
|
||||
void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap);
|
||||
|
||||
strbuf *strbuf_new_for_agent_query(void);
|
||||
void strbuf_finalise_agent_query(strbuf *buf);
|
||||
|
||||
/* String-to-Unicode converters that auto-allocate the destination and
|
||||
* work around the rather deficient interface of mb_to_wc.
|
||||
*
|
||||
@@ -70,10 +72,6 @@ struct bufchain_tag {
|
||||
struct bufchain_granule *head, *tail;
|
||||
int buffersize; /* current amount of buffered data */
|
||||
};
|
||||
#ifndef BUFCHAIN_TYPEDEF
|
||||
typedef struct bufchain_tag bufchain; /* rest of declaration in misc.c */
|
||||
#define BUFCHAIN_TYPEDEF
|
||||
#endif
|
||||
|
||||
void bufchain_init(bufchain *ch);
|
||||
void bufchain_clear(bufchain *ch);
|
||||
@@ -82,11 +80,21 @@ void bufchain_add(bufchain *ch, const void *data, int len);
|
||||
void bufchain_prefix(bufchain *ch, void **data, int *len);
|
||||
void bufchain_consume(bufchain *ch, int len);
|
||||
void bufchain_fetch(bufchain *ch, void *data, int len);
|
||||
void bufchain_fetch_consume(bufchain *ch, void *data, int len);
|
||||
int bufchain_try_fetch_consume(bufchain *ch, void *data, int len);
|
||||
|
||||
int validate_manual_hostkey(char *key);
|
||||
|
||||
struct tm ltime(void);
|
||||
|
||||
ptrlen make_ptrlen(const void *ptr, size_t len);
|
||||
int ptrlen_eq_string(ptrlen pl, const char *str);
|
||||
char *mkstr(ptrlen pl);
|
||||
int string_length_for_printf(size_t);
|
||||
/* Derive two printf arguments from a ptrlen, suitable for "%.*s" */
|
||||
#define PTRLEN_PRINTF(pl) \
|
||||
string_length_for_printf((pl).len), (const char *)(pl).ptr
|
||||
|
||||
/* Wipe sensitive data out of memory that's about to be freed. Simpler
|
||||
* than memset because we don't need the fill char parameter; also
|
||||
* attempts (by fiddly use of volatile) to inhibit the compiler from
|
||||
@@ -101,23 +109,6 @@ void smemclr(void *b, size_t len);
|
||||
* by the 'eq' in the name. */
|
||||
int smemeq(const void *av, const void *bv, size_t len);
|
||||
|
||||
/* Extracts an SSH-marshalled string from the start of *data. If
|
||||
* successful (*datalen is not too small), advances data/datalen past
|
||||
* the string and returns a pointer to the string itself and its
|
||||
* length in *stringlen. Otherwise does nothing and returns NULL.
|
||||
*
|
||||
* Like strchr, this function can discard const from its parameter.
|
||||
* Treat it as if it was a family of two functions, one returning a
|
||||
* non-const string given a non-const pointer, and one taking and
|
||||
* returning const. */
|
||||
void *get_ssh_string(int *datalen, const void **data, int *stringlen);
|
||||
/* Extracts an SSH uint32, similarly. Returns TRUE on success, and
|
||||
* leaves the extracted value in *ret. */
|
||||
int get_ssh_uint32(int *datalen, const void **data, unsigned *ret);
|
||||
/* Given a not-necessarily-zero-terminated string in (length,data)
|
||||
* form, check if it equals an ordinary C zero-terminated string. */
|
||||
int match_ssh_id(int stringlen, const void *string, const char *id);
|
||||
|
||||
char *buildinfo(const char *newline);
|
||||
|
||||
/*
|
||||
|
||||
29
source/putty/network.h
vendored
29
source/putty/network.h
vendored
@@ -13,26 +13,16 @@
|
||||
#ifndef PUTTY_NETWORK_H
|
||||
#define PUTTY_NETWORK_H
|
||||
|
||||
#ifndef DONE_TYPEDEFS
|
||||
#define DONE_TYPEDEFS
|
||||
typedef struct conf_tag Conf;
|
||||
typedef struct backend_tag Backend;
|
||||
typedef struct terminal_tag Terminal;
|
||||
#endif
|
||||
#include "defs.h"
|
||||
|
||||
typedef struct SockAddr_tag *SockAddr;
|
||||
/* pay attention to levels of indirection */
|
||||
typedef struct socket_function_table **Socket;
|
||||
typedef struct plug_function_table **Plug;
|
||||
|
||||
struct socket_function_table {
|
||||
struct Socket_vtable {
|
||||
Plug(*plug) (Socket s, Plug p);
|
||||
/* use a different plug (return the old one) */
|
||||
/* if p is NULL, it doesn't change the plug */
|
||||
/* but it does return the one it's using */
|
||||
void (*close) (Socket s);
|
||||
int (*write) (Socket s, const char *data, int len);
|
||||
int (*write_oob) (Socket s, const char *data, int len);
|
||||
int (*write) (Socket s, const void *data, int len);
|
||||
int (*write_oob) (Socket s, const void *data, int len);
|
||||
void (*write_eof) (Socket s);
|
||||
void (*flush) (Socket s);
|
||||
void (*set_frozen) (Socket s, int is_frozen);
|
||||
@@ -44,7 +34,7 @@ struct socket_function_table {
|
||||
typedef union { void *p; int i; } accept_ctx_t;
|
||||
typedef Socket (*accept_fn_t)(accept_ctx_t ctx, Plug plug);
|
||||
|
||||
struct plug_function_table {
|
||||
struct Plug_vtable {
|
||||
void (*log)(Plug p, int type, SockAddr addr, int port,
|
||||
const char *error_msg, int error_code);
|
||||
/*
|
||||
@@ -227,6 +217,11 @@ char *get_hostname(void);
|
||||
*/
|
||||
Socket new_error_socket(const char *errmsg, Plug plug);
|
||||
|
||||
/*
|
||||
* Trivial plug that does absolutely nothing. Found in nullplug.c.
|
||||
*/
|
||||
extern Plug nullplug;
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Functions defined outside the network code, which have to be
|
||||
* declared in this header file rather than the main putty.h because
|
||||
@@ -239,10 +234,6 @@ Socket new_error_socket(const char *errmsg, Plug plug);
|
||||
void backend_socket_log(void *frontend, int type, SockAddr addr, int port,
|
||||
const char *error_msg, int error_code, Conf *conf,
|
||||
int session_started);
|
||||
#ifndef BUFCHAIN_TYPEDEF
|
||||
typedef struct bufchain_tag bufchain; /* rest of declaration in misc.c */
|
||||
#define BUFCHAIN_TYPEDEF
|
||||
#endif
|
||||
void log_proxy_stderr(Plug plug, bufchain *buf, const void *vdata, int len);
|
||||
|
||||
#endif
|
||||
|
||||
42
source/putty/nullplug.c
vendored
Normal file
42
source/putty/nullplug.c
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* nullplug.c: provide a null implementation of the Plug vtable which
|
||||
* ignores all calls. Occasionally useful in cases where we want to
|
||||
* make a network connection just to see if it works, but not do
|
||||
* anything with it afterwards except close it again.
|
||||
*/
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
static void nullplug_socket_log(Plug plug, int type, SockAddr addr, int port,
|
||||
const char *error_msg, int error_code)
|
||||
{
|
||||
}
|
||||
|
||||
static void nullplug_closing(Plug plug, const char *error_msg, int error_code,
|
||||
int calling_back)
|
||||
{
|
||||
}
|
||||
|
||||
static void nullplug_receive(Plug plug, int urgent, char *data, int len)
|
||||
{
|
||||
}
|
||||
|
||||
static void nullplug_sent(Plug plug, int bufsize)
|
||||
{
|
||||
}
|
||||
|
||||
static const Plug_vtable nullplug_plugvt = {
|
||||
nullplug_socket_log,
|
||||
nullplug_closing,
|
||||
nullplug_receive,
|
||||
nullplug_sent,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const Plug_vtable *nullplug_plugvt_ptr = &nullplug_plugvt;
|
||||
|
||||
/*
|
||||
* There's a singleton instance of nullplug, because it's not
|
||||
* interesting enough to worry about making more than one of them.
|
||||
*/
|
||||
Plug nullplug = &nullplug_plugvt_ptr;
|
||||
31
source/putty/pageant.h
vendored
31
source/putty/pageant.h
vendored
@@ -5,12 +5,11 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
* FIXME: it would be nice not to have this arbitrary limit. It's
|
||||
* currently needed because the Windows Pageant IPC system needs an
|
||||
* upper bound known to the client, but it's also reused as a basic
|
||||
* sanity check on incoming messages' length fields.
|
||||
* Upper limit on length of any agent message. Used as a basic sanity
|
||||
* check on messages' length fields, and used by the Windows Pageant
|
||||
* client IPC to decide how large a file mapping to allocate.
|
||||
*/
|
||||
#define AGENT_MAX_MSGLEN 8192
|
||||
#define AGENT_MAX_MSGLEN 262144
|
||||
|
||||
typedef void (*pageant_logfn_t)(void *logctx, const char *fmt, va_list ap);
|
||||
|
||||
@@ -28,21 +27,26 @@ void pageant_init(void);
|
||||
* Returns a fully formatted message as output, *with* its initial
|
||||
* length field, and sets *outlen to the full size of that message.
|
||||
*/
|
||||
void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
|
||||
void *logctx, pageant_logfn_t logfn);
|
||||
void pageant_handle_msg(BinarySink *bs,
|
||||
const void *msg, int msglen,
|
||||
void *logctx, pageant_logfn_t logfn);
|
||||
|
||||
/*
|
||||
* Construct a failure response. Useful for agent front ends which
|
||||
* suffer a problem before they even get to pageant_handle_msg.
|
||||
*
|
||||
* 'log_reason' is only used if logfn is not NULL.
|
||||
*/
|
||||
void *pageant_failure_msg(int *outlen);
|
||||
void pageant_failure_msg(BinarySink *bs,
|
||||
const char *log_reason,
|
||||
void *logctx, pageant_logfn_t logfn);
|
||||
|
||||
/*
|
||||
* Construct a list of public keys, just as the two LIST_IDENTITIES
|
||||
* requests would have returned them.
|
||||
*/
|
||||
void *pageant_make_keylist1(int *length);
|
||||
void *pageant_make_keylist2(int *length);
|
||||
void pageant_make_keylist1(BinarySink *);
|
||||
void pageant_make_keylist2(BinarySink *);
|
||||
|
||||
/*
|
||||
* Accessor functions for Pageant's internal key lists. Fetch the nth
|
||||
@@ -74,13 +78,13 @@ void keylist_update(void);
|
||||
/*
|
||||
* Functions to establish a listening socket speaking the SSH agent
|
||||
* protocol. Call pageant_listener_new() to set up a state; then
|
||||
* create a socket using the returned pointer as a Plug; then call
|
||||
* create a socket using the returned Plug; then call
|
||||
* pageant_listener_got_socket() to give the listening state its own
|
||||
* socket pointer. Also, provide a logging function later if you want
|
||||
* to.
|
||||
*/
|
||||
struct pageant_listen_state;
|
||||
struct pageant_listen_state *pageant_listener_new(void);
|
||||
struct pageant_listen_state *pageant_listener_new(Plug *plug);
|
||||
void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock);
|
||||
void pageant_listener_set_logfn(struct pageant_listen_state *pl,
|
||||
void *logctx, pageant_logfn_t logfn);
|
||||
@@ -125,8 +129,7 @@ struct pageant_pubkey {
|
||||
/* Everything needed to identify a public key found by
|
||||
* pageant_enum_keys and pass it back to the agent or other code
|
||||
* later */
|
||||
void *blob;
|
||||
int bloblen;
|
||||
strbuf *blob;
|
||||
char *comment;
|
||||
int ssh_version;
|
||||
};
|
||||
|
||||
2
source/putty/pgssapi.c
vendored
2
source/putty/pgssapi.c
vendored
@@ -43,7 +43,7 @@ static const gss_OID_desc oids[] = {
|
||||
{6, (void *)"\x2b\x06\x01\x05\x06\x02"},
|
||||
/* corresponding to an object-identifier value of
|
||||
* {iso(1) org(3) dod(6) internet(1) security(5)
|
||||
* nametypes(6) gss-host-based-services(2)). The constant
|
||||
* nametypes(6) gss-host-based-services(2))}. The constant
|
||||
* GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
|
||||
* to that gss_OID_desc. This is a deprecated OID value, and
|
||||
* implementations wishing to support hostbased-service names
|
||||
|
||||
37
source/putty/pgssapi.h
vendored
37
source/putty/pgssapi.h
vendored
@@ -58,6 +58,7 @@ typedef void * gss_name_t;
|
||||
typedef void * gss_cred_id_t;
|
||||
|
||||
typedef OM_uint32 gss_qop_t;
|
||||
typedef int gss_cred_usage_t;
|
||||
|
||||
/* Flag bits for context-level services. */
|
||||
|
||||
@@ -76,6 +77,13 @@ typedef OM_uint32 gss_qop_t;
|
||||
#define GSS_C_INITIATE 1
|
||||
#define GSS_C_ACCEPT 2
|
||||
|
||||
/*-
|
||||
* RFC 2744 Page 86
|
||||
* Expiration time of 2^32-1 seconds means infinite lifetime for a
|
||||
* credential or security context
|
||||
*/
|
||||
#define GSS_C_INDEFINITE 0xfffffffful
|
||||
|
||||
/* Status code types for gss_display_status */
|
||||
#define GSS_C_GSS_CODE 1
|
||||
#define GSS_C_MECH_CODE 2
|
||||
@@ -256,6 +264,13 @@ typedef OM_uint32 (GSS_CC *t_gss_get_mic)
|
||||
const gss_buffer_t /*message_buffer*/,
|
||||
gss_buffer_t /*msg_token*/);
|
||||
|
||||
typedef OM_uint32 (GSS_CC *t_gss_verify_mic)
|
||||
(OM_uint32 * /*minor_status*/,
|
||||
const gss_ctx_id_t /*context_handle*/,
|
||||
const gss_buffer_t /*message_buffer*/,
|
||||
const gss_buffer_t /*msg_token*/,
|
||||
gss_qop_t * /*qop_state*/);
|
||||
|
||||
typedef OM_uint32 (GSS_CC *t_gss_display_status)
|
||||
(OM_uint32 * /*minor_status*/,
|
||||
OM_uint32 /*status_value*/,
|
||||
@@ -280,15 +295,37 @@ typedef OM_uint32 (GSS_CC *t_gss_release_buffer)
|
||||
(OM_uint32 * /*minor_status*/,
|
||||
gss_buffer_t /*buffer*/);
|
||||
|
||||
typedef OM_uint32 (GSS_CC *t_gss_acquire_cred)
|
||||
(OM_uint32 * /*minor_status*/,
|
||||
const gss_name_t /*desired_name*/,
|
||||
OM_uint32 /*time_req*/,
|
||||
const gss_OID_set /*desired_mechs*/,
|
||||
gss_cred_usage_t /*cred_usage*/,
|
||||
gss_cred_id_t * /*output_cred_handle*/,
|
||||
gss_OID_set * /*actual_mechs*/,
|
||||
OM_uint32 * /*time_rec*/);
|
||||
|
||||
typedef OM_uint32 (GSS_CC *t_gss_inquire_cred_by_mech)
|
||||
(OM_uint32 * /*minor_status*/,
|
||||
const gss_cred_id_t /*cred_handle*/,
|
||||
const gss_OID /*mech_type*/,
|
||||
gss_name_t * /*name*/,
|
||||
OM_uint32 * /*initiator_lifetime*/,
|
||||
OM_uint32 * /*acceptor_lifetime*/,
|
||||
gss_cred_usage_t * /*cred_usage*/);
|
||||
|
||||
struct gssapi_functions {
|
||||
t_gss_delete_sec_context delete_sec_context;
|
||||
t_gss_display_status display_status;
|
||||
t_gss_get_mic get_mic;
|
||||
t_gss_verify_mic verify_mic;
|
||||
t_gss_import_name import_name;
|
||||
t_gss_init_sec_context init_sec_context;
|
||||
t_gss_release_buffer release_buffer;
|
||||
t_gss_release_cred release_cred;
|
||||
t_gss_release_name release_name;
|
||||
t_gss_acquire_cred acquire_cred;
|
||||
t_gss_inquire_cred_by_mech inquire_cred_by_mech;
|
||||
};
|
||||
|
||||
#endif /* NO_GSSAPI */
|
||||
|
||||
561
source/putty/portfwd.c
vendored
561
source/putty/portfwd.c
vendored
@@ -2,35 +2,33 @@
|
||||
* SSH port forwarding.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
/*
|
||||
* Enumeration of values that live in the 'socks_state' field of
|
||||
* struct PortForwarding.
|
||||
*/
|
||||
typedef enum {
|
||||
SOCKS_NONE, /* direct connection (no SOCKS, or SOCKS already done) */
|
||||
SOCKS_INITIAL, /* don't know if we're SOCKS 4 or 5 yet */
|
||||
SOCKS_4, /* expect a SOCKS 4 (or 4A) connection message */
|
||||
SOCKS_5_INITIAL, /* expect a SOCKS 5 preliminary message */
|
||||
SOCKS_5_CONNECT /* expect a SOCKS 5 connection message */
|
||||
} SocksState;
|
||||
|
||||
struct PortForwarding {
|
||||
const struct plug_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
struct ssh_channel *c; /* channel structure held by ssh.c */
|
||||
void *backhandle; /* instance of SSH backend itself */
|
||||
/* Note that backhandle need not be filled in if c is non-NULL */
|
||||
Socket s;
|
||||
int throttled, throttle_override;
|
||||
int ready;
|
||||
/*
|
||||
* `dynamic' does double duty. It's set to 0 for an ordinary
|
||||
* forwarded port, and nonzero for SOCKS-style dynamic port
|
||||
* forwarding; but the nonzero values are also a state machine
|
||||
* tracking where the SOCKS exchange has got to.
|
||||
*/
|
||||
int dynamic;
|
||||
SocksState socks_state;
|
||||
/*
|
||||
* `hostname' and `port' are the real hostname and port, once
|
||||
* we know what we're connecting to.
|
||||
@@ -38,36 +36,28 @@ struct PortForwarding {
|
||||
char *hostname;
|
||||
int port;
|
||||
/*
|
||||
* `socksbuf' is the buffer we use to accumulate a SOCKS request.
|
||||
* `socksbuf' is the buffer we use to accumulate the initial SOCKS
|
||||
* segment of the incoming data, plus anything after that that we
|
||||
* receive before we're ready to send data to the SSH server.
|
||||
*/
|
||||
char *socksbuf;
|
||||
int sockslen, sockssize;
|
||||
/*
|
||||
* When doing dynamic port forwarding, we can receive
|
||||
* connection data before we are actually able to send it; so
|
||||
* we may have to temporarily hold some in a dynamically
|
||||
* allocated buffer here.
|
||||
*/
|
||||
void *buffer;
|
||||
int buflen;
|
||||
strbuf *socksbuf;
|
||||
size_t socksbuf_consumed;
|
||||
|
||||
const Plug_vtable *plugvt;
|
||||
};
|
||||
|
||||
struct PortListener {
|
||||
const struct plug_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
void *backhandle; /* instance of SSH backend itself */
|
||||
Socket s;
|
||||
/*
|
||||
* `dynamic' is set to 0 for an ordinary forwarded port, and
|
||||
* nonzero for SOCKS-style dynamic port forwarding.
|
||||
*/
|
||||
int dynamic;
|
||||
int is_dynamic;
|
||||
/*
|
||||
* `hostname' and `port' are the real hostname and port, for
|
||||
* ordinary forwardings.
|
||||
*/
|
||||
char *hostname;
|
||||
int port;
|
||||
|
||||
const Plug_vtable *plugvt;
|
||||
};
|
||||
|
||||
static struct PortForwarding *new_portfwd_state(void)
|
||||
@@ -75,8 +65,6 @@ static struct PortForwarding *new_portfwd_state(void)
|
||||
struct PortForwarding *pf = snew(struct PortForwarding);
|
||||
pf->hostname = NULL;
|
||||
pf->socksbuf = NULL;
|
||||
pf->sockslen = pf->sockssize = 0;
|
||||
pf->buffer = NULL;
|
||||
return pf;
|
||||
}
|
||||
|
||||
@@ -85,8 +73,8 @@ static void free_portfwd_state(struct PortForwarding *pf)
|
||||
if (!pf)
|
||||
return;
|
||||
sfree(pf->hostname);
|
||||
sfree(pf->socksbuf);
|
||||
sfree(pf->buffer);
|
||||
if (pf->socksbuf)
|
||||
strbuf_free(pf->socksbuf);
|
||||
sfree(pf);
|
||||
}
|
||||
|
||||
@@ -120,7 +108,7 @@ static void pfl_log(Plug plug, int type, SockAddr addr, int port,
|
||||
static void pfd_closing(Plug plug, const char *error_msg, int error_code,
|
||||
int calling_back)
|
||||
{
|
||||
struct PortForwarding *pf = (struct PortForwarding *) plug;
|
||||
struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt);
|
||||
|
||||
if (error_msg) {
|
||||
/*
|
||||
@@ -169,207 +157,238 @@ static void wrap_send_port_open(void *channel, const char *hostname, int port,
|
||||
sfree(description);
|
||||
}
|
||||
|
||||
static char *ipv4_to_string(unsigned ipv4)
|
||||
{
|
||||
return dupprintf("%u.%u.%u.%u",
|
||||
(ipv4 >> 24) & 0xFF, (ipv4 >> 16) & 0xFF,
|
||||
(ipv4 >> 8) & 0xFF, (ipv4 ) & 0xFF);
|
||||
}
|
||||
|
||||
static char *ipv6_to_string(ptrlen ipv6)
|
||||
{
|
||||
const unsigned char *addr = ipv6.ptr;
|
||||
assert(ipv6.len == 16);
|
||||
return dupprintf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
|
||||
(unsigned)GET_16BIT_MSB_FIRST(addr + 0),
|
||||
(unsigned)GET_16BIT_MSB_FIRST(addr + 2),
|
||||
(unsigned)GET_16BIT_MSB_FIRST(addr + 4),
|
||||
(unsigned)GET_16BIT_MSB_FIRST(addr + 6),
|
||||
(unsigned)GET_16BIT_MSB_FIRST(addr + 8),
|
||||
(unsigned)GET_16BIT_MSB_FIRST(addr + 10),
|
||||
(unsigned)GET_16BIT_MSB_FIRST(addr + 12),
|
||||
(unsigned)GET_16BIT_MSB_FIRST(addr + 14));
|
||||
}
|
||||
|
||||
static void pfd_receive(Plug plug, int urgent, char *data, int len)
|
||||
{
|
||||
struct PortForwarding *pf = (struct PortForwarding *) plug;
|
||||
if (pf->dynamic) {
|
||||
while (len--) {
|
||||
if (pf->sockslen >= pf->sockssize) {
|
||||
pf->sockssize = pf->sockslen * 5 / 4 + 256;
|
||||
pf->socksbuf = sresize(pf->socksbuf, pf->sockssize, char);
|
||||
}
|
||||
pf->socksbuf[pf->sockslen++] = *data++;
|
||||
struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt);
|
||||
|
||||
/*
|
||||
* Now check what's in the buffer to see if it's a
|
||||
* valid and complete message in the SOCKS exchange.
|
||||
*/
|
||||
if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 4) &&
|
||||
pf->socksbuf[0] == 4) {
|
||||
/*
|
||||
* SOCKS 4.
|
||||
*/
|
||||
if (pf->dynamic == 1)
|
||||
pf->dynamic = 0x4000;
|
||||
if (pf->sockslen < 2)
|
||||
continue; /* don't have command code yet */
|
||||
if (pf->socksbuf[1] != 1) {
|
||||
/* Not CONNECT. */
|
||||
/* Send back a SOCKS 4 error before closing. */
|
||||
char data[8];
|
||||
memset(data, 0, sizeof(data));
|
||||
data[1] = 91; /* generic `request rejected' */
|
||||
sk_write(pf->s, data, 8);
|
||||
pfd_close(pf);
|
||||
return;
|
||||
}
|
||||
if (pf->sockslen <= 8)
|
||||
continue; /* haven't started user/hostname */
|
||||
if (pf->socksbuf[pf->sockslen-1] != 0)
|
||||
continue; /* haven't _finished_ user/hostname */
|
||||
/*
|
||||
* Now we have a full SOCKS 4 request. Check it to
|
||||
* see if it's a SOCKS 4A request.
|
||||
*/
|
||||
if (pf->socksbuf[4] == 0 && pf->socksbuf[5] == 0 &&
|
||||
pf->socksbuf[6] == 0 && pf->socksbuf[7] != 0) {
|
||||
/*
|
||||
* It's SOCKS 4A. So if we haven't yet
|
||||
* collected the host name, we should continue
|
||||
* waiting for data in order to do so; if we
|
||||
* have, we can go ahead.
|
||||
*/
|
||||
int len;
|
||||
if (pf->dynamic == 0x4000) {
|
||||
pf->dynamic = 0x4001;
|
||||
pf->sockslen = 8; /* reset buffer to overwrite name */
|
||||
continue;
|
||||
}
|
||||
pf->socksbuf[0] = 0; /* reply version code */
|
||||
pf->socksbuf[1] = 90; /* request granted */
|
||||
sk_write(pf->s, pf->socksbuf, 8);
|
||||
len = pf->sockslen - 8;
|
||||
pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2);
|
||||
pf->hostname = snewn(len+1, char);
|
||||
pf->hostname[len] = '\0';
|
||||
memcpy(pf->hostname, pf->socksbuf + 8, len);
|
||||
goto connect;
|
||||
} else {
|
||||
/*
|
||||
* It's SOCKS 4, which means we should format
|
||||
* the IP address into the hostname string and
|
||||
* then just go.
|
||||
*/
|
||||
pf->socksbuf[0] = 0; /* reply version code */
|
||||
pf->socksbuf[1] = 90; /* request granted */
|
||||
sk_write(pf->s, pf->socksbuf, 8);
|
||||
pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2);
|
||||
pf->hostname = dupprintf("%d.%d.%d.%d",
|
||||
(unsigned char)pf->socksbuf[4],
|
||||
(unsigned char)pf->socksbuf[5],
|
||||
(unsigned char)pf->socksbuf[6],
|
||||
(unsigned char)pf->socksbuf[7]);
|
||||
goto connect;
|
||||
}
|
||||
}
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 5) &&
|
||||
pf->socksbuf[0] == 5) {
|
||||
/*
|
||||
* SOCKS 5.
|
||||
*/
|
||||
if (pf->dynamic == 1)
|
||||
pf->dynamic = 0x5000;
|
||||
if (pf->socks_state != SOCKS_NONE) {
|
||||
BinarySource src[1];
|
||||
|
||||
if (pf->dynamic == 0x5000) {
|
||||
int i, method;
|
||||
char data[2];
|
||||
/*
|
||||
* We're receiving a set of method identifiers.
|
||||
*/
|
||||
if (pf->sockslen < 2)
|
||||
continue; /* no method count yet */
|
||||
if (pf->sockslen < 2 + (unsigned char)pf->socksbuf[1])
|
||||
continue; /* no methods yet */
|
||||
method = 0xFF; /* invalid */
|
||||
for (i = 0; i < (unsigned char)pf->socksbuf[1]; i++)
|
||||
if (pf->socksbuf[2+i] == 0) {
|
||||
method = 0;/* no auth */
|
||||
break;
|
||||
}
|
||||
data[0] = 5;
|
||||
data[1] = method;
|
||||
sk_write(pf->s, data, 2);
|
||||
pf->dynamic = 0x5001;
|
||||
pf->sockslen = 0; /* re-empty the buffer */
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Store all the data we've got in socksbuf.
|
||||
*/
|
||||
put_data(pf->socksbuf, data, len);
|
||||
|
||||
if (pf->dynamic == 0x5001) {
|
||||
/*
|
||||
* We're receiving a SOCKS request.
|
||||
*/
|
||||
unsigned char reply[10]; /* SOCKS5 atyp=1 reply */
|
||||
int atype, alen = 0;
|
||||
/*
|
||||
* Check the start of socksbuf to see if it's a valid and
|
||||
* complete message in the SOCKS exchange.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pre-fill reply packet.
|
||||
* In all cases, we set BND.{HOST,ADDR} to 0.0.0.0:0
|
||||
* (atyp=1) in the reply; if we succeed, we don't know
|
||||
* the right answers, and if we fail, they should be
|
||||
* ignored.
|
||||
*/
|
||||
memset(reply, 0, lenof(reply));
|
||||
reply[0] = 5; /* VER */
|
||||
reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */
|
||||
if (pf->socks_state == SOCKS_INITIAL) {
|
||||
/* Preliminary: check the first byte of the data (which we
|
||||
* _must_ have by now) to find out which SOCKS major
|
||||
* version we're speaking. */
|
||||
switch (pf->socksbuf->u[0]) {
|
||||
case 4:
|
||||
pf->socks_state = SOCKS_4;
|
||||
break;
|
||||
case 5:
|
||||
pf->socks_state = SOCKS_5_INITIAL;
|
||||
break;
|
||||
default:
|
||||
pfd_close(pf); /* unrecognised version */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pf->sockslen < 6) continue;
|
||||
atype = (unsigned char)pf->socksbuf[3];
|
||||
if (atype == 1) /* IPv4 address */
|
||||
alen = 4;
|
||||
if (atype == 4) /* IPv6 address */
|
||||
alen = 16;
|
||||
if (atype == 3) /* domain name has leading length */
|
||||
alen = 1 + (unsigned char)pf->socksbuf[4];
|
||||
if (pf->sockslen < 6 + alen) continue;
|
||||
if (pf->socksbuf[1] != 1 || pf->socksbuf[2] != 0) {
|
||||
/* Not CONNECT or reserved field nonzero - error */
|
||||
reply[1] = 1; /* generic failure */
|
||||
sk_write(pf->s, (char *) reply, lenof(reply));
|
||||
pfd_close(pf);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Now we have a viable connect request. Switch
|
||||
* on atype.
|
||||
*/
|
||||
pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+4+alen);
|
||||
if (atype == 1) {
|
||||
/* REP=0 (success) already */
|
||||
sk_write(pf->s, (char *) reply, lenof(reply));
|
||||
pf->hostname = dupprintf("%d.%d.%d.%d",
|
||||
(unsigned char)pf->socksbuf[4],
|
||||
(unsigned char)pf->socksbuf[5],
|
||||
(unsigned char)pf->socksbuf[6],
|
||||
(unsigned char)pf->socksbuf[7]);
|
||||
goto connect;
|
||||
} else if (atype == 3) {
|
||||
/* REP=0 (success) already */
|
||||
sk_write(pf->s, (char *) reply, lenof(reply));
|
||||
pf->hostname = snewn(alen, char);
|
||||
pf->hostname[alen-1] = '\0';
|
||||
memcpy(pf->hostname, pf->socksbuf + 5, alen-1);
|
||||
goto connect;
|
||||
} else {
|
||||
/*
|
||||
* Unknown address type. (FIXME: support IPv6!)
|
||||
*/
|
||||
reply[1] = 8; /* atype not supported */
|
||||
sk_write(pf->s, (char *) reply, lenof(reply));
|
||||
pfd_close(pf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
BinarySource_BARE_INIT(src, pf->socksbuf->u, pf->socksbuf->len);
|
||||
get_data(src, pf->socksbuf_consumed);
|
||||
|
||||
/*
|
||||
* If we get here without either having done `continue'
|
||||
* or `goto connect', it must be because there is no
|
||||
* sensible interpretation of what's in our buffer. So
|
||||
* close the connection rudely.
|
||||
*/
|
||||
pfd_close(pf);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
while (pf->socks_state != SOCKS_NONE) {
|
||||
unsigned socks_version, message_type, reserved_byte;
|
||||
unsigned reply_code, port, ipv4, method;
|
||||
ptrlen methods;
|
||||
const char *socks4_hostname;
|
||||
strbuf *output;
|
||||
|
||||
switch (pf->socks_state) {
|
||||
case SOCKS_INITIAL:
|
||||
case SOCKS_NONE:
|
||||
assert(0 && "These case values cannot appear");
|
||||
|
||||
case SOCKS_4:
|
||||
/* SOCKS 4/4A connect message */
|
||||
socks_version = get_byte(src);
|
||||
message_type = get_byte(src);
|
||||
|
||||
if (get_err(src) == BSE_OUT_OF_DATA)
|
||||
return;
|
||||
if (socks_version == 4 && message_type == 1) {
|
||||
/* CONNECT message */
|
||||
int name_based = FALSE;
|
||||
|
||||
port = get_uint16(src);
|
||||
ipv4 = get_uint32(src);
|
||||
if (ipv4 > 0x00000000 && ipv4 < 0x00000100) {
|
||||
/*
|
||||
* Addresses in this range indicate the SOCKS 4A
|
||||
* extension to specify a hostname, which comes
|
||||
* after the username.
|
||||
*/
|
||||
name_based = TRUE;
|
||||
}
|
||||
get_asciz(src); /* skip username */
|
||||
socks4_hostname = name_based ? get_asciz(src) : NULL;
|
||||
|
||||
if (get_err(src) == BSE_OUT_OF_DATA)
|
||||
return;
|
||||
if (get_err(src))
|
||||
goto socks4_reject;
|
||||
|
||||
pf->port = port;
|
||||
if (name_based) {
|
||||
pf->hostname = dupstr(socks4_hostname);
|
||||
} else {
|
||||
pf->hostname = ipv4_to_string(ipv4);
|
||||
}
|
||||
|
||||
output = strbuf_new();
|
||||
put_byte(output, 0); /* reply version */
|
||||
put_byte(output, 90); /* SOCKS 4 'request granted' */
|
||||
put_uint16(output, 0); /* null port field */
|
||||
put_uint32(output, 0); /* null address field */
|
||||
sk_write(pf->s, output->u, output->len);
|
||||
strbuf_free(output);
|
||||
|
||||
pf->socks_state = SOCKS_NONE;
|
||||
pf->socksbuf_consumed = src->pos;
|
||||
break;
|
||||
}
|
||||
|
||||
socks4_reject:
|
||||
output = strbuf_new();
|
||||
put_byte(output, 0); /* reply version */
|
||||
put_byte(output, 91); /* SOCKS 4 'request rejected' */
|
||||
put_uint16(output, 0); /* null port field */
|
||||
put_uint32(output, 0); /* null address field */
|
||||
sk_write(pf->s, output->u, output->len);
|
||||
strbuf_free(output);
|
||||
pfd_close(pf);
|
||||
return;
|
||||
|
||||
case SOCKS_5_INITIAL:
|
||||
/* SOCKS 5 initial method list */
|
||||
socks_version = get_byte(src);
|
||||
methods = get_pstring(src);
|
||||
|
||||
method = 0xFF; /* means 'no usable method found' */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < methods.len; i++) {
|
||||
if (((const unsigned char *)methods.ptr)[i] == 0 ) {
|
||||
method = 0; /* no auth */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (get_err(src) == BSE_OUT_OF_DATA)
|
||||
return;
|
||||
if (get_err(src))
|
||||
method = 0xFF;
|
||||
|
||||
output = strbuf_new();
|
||||
put_byte(output, 5); /* SOCKS version */
|
||||
put_byte(output, method); /* selected auth method */
|
||||
sk_write(pf->s, output->u, output->len);
|
||||
strbuf_free(output);
|
||||
|
||||
if (method == 0xFF) {
|
||||
pfd_close(pf);
|
||||
return;
|
||||
}
|
||||
|
||||
pf->socks_state = SOCKS_5_CONNECT;
|
||||
pf->socksbuf_consumed = src->pos;
|
||||
break;
|
||||
|
||||
case SOCKS_5_CONNECT:
|
||||
/* SOCKS 5 connect message */
|
||||
socks_version = get_byte(src);
|
||||
message_type = get_byte(src);
|
||||
reserved_byte = get_byte(src);
|
||||
|
||||
if (socks_version == 5 && message_type == 1 &&
|
||||
reserved_byte == 0) {
|
||||
|
||||
reply_code = 0; /* success */
|
||||
|
||||
switch (get_byte(src)) {
|
||||
case 1: /* IPv4 */
|
||||
pf->hostname = ipv4_to_string(get_uint32(src));
|
||||
break;
|
||||
case 4: /* IPv6 */
|
||||
pf->hostname = ipv6_to_string(get_data(src, 16));
|
||||
break;
|
||||
case 3: /* unresolved domain name */
|
||||
pf->hostname = mkstr(get_pstring(src));
|
||||
break;
|
||||
default:
|
||||
pf->hostname = NULL;
|
||||
reply_code = 8; /* address type not supported */
|
||||
break;
|
||||
}
|
||||
|
||||
pf->port = get_uint16(src);
|
||||
} else {
|
||||
reply_code = 7; /* command not supported */
|
||||
}
|
||||
|
||||
if (get_err(src) == BSE_OUT_OF_DATA)
|
||||
return;
|
||||
if (get_err(src))
|
||||
reply_code = 1; /* general server failure */
|
||||
|
||||
output = strbuf_new();
|
||||
put_byte(output, 5); /* SOCKS version */
|
||||
put_byte(output, reply_code);
|
||||
put_byte(output, 0); /* reserved */
|
||||
put_byte(output, 1); /* IPv4 address follows */
|
||||
put_uint32(output, 0); /* bound IPv4 address (unused) */
|
||||
put_uint16(output, 0); /* bound port number (unused) */
|
||||
sk_write(pf->s, output->u, output->len);
|
||||
strbuf_free(output);
|
||||
|
||||
if (reply_code != 0) {
|
||||
pfd_close(pf);
|
||||
return;
|
||||
}
|
||||
|
||||
pf->socks_state = SOCKS_NONE;
|
||||
pf->socksbuf_consumed = src->pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We come here when we're ready to make an actual
|
||||
* connection.
|
||||
*/
|
||||
connect:
|
||||
sfree(pf->socksbuf);
|
||||
pf->socksbuf = NULL;
|
||||
|
||||
/*
|
||||
* Freeze the socket until the SSH server confirms the
|
||||
@@ -385,17 +404,6 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len)
|
||||
/* asks to forward to the specified host/port for this */
|
||||
wrap_send_port_open(pf->c, pf->hostname, pf->port, pf->s);
|
||||
}
|
||||
pf->dynamic = 0;
|
||||
|
||||
/*
|
||||
* If there's any data remaining in our current buffer,
|
||||
* save it to be sent on pfd_confirm().
|
||||
*/
|
||||
if (len > 0) {
|
||||
pf->buffer = snewn(len, char);
|
||||
memcpy(pf->buffer, data, len);
|
||||
pf->buflen = len;
|
||||
}
|
||||
}
|
||||
if (pf->ready) {
|
||||
if (sshfwd_write(pf->c, data, len) > 0) {
|
||||
@@ -407,12 +415,20 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len)
|
||||
|
||||
static void pfd_sent(Plug plug, int bufsize)
|
||||
{
|
||||
struct PortForwarding *pf = (struct PortForwarding *) plug;
|
||||
struct PortForwarding *pf = FROMFIELD(plug, struct PortForwarding, plugvt);
|
||||
|
||||
if (pf->c)
|
||||
sshfwd_unthrottle(pf->c, bufsize);
|
||||
}
|
||||
|
||||
static const Plug_vtable PortForwarding_plugvt = {
|
||||
pfd_log,
|
||||
pfd_closing,
|
||||
pfd_receive,
|
||||
pfd_sent,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Called when receiving a PORT OPEN from the server to make a
|
||||
* connection to a destination host.
|
||||
@@ -423,17 +439,9 @@ static void pfd_sent(Plug plug, int bufsize)
|
||||
char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
|
||||
void *c, Conf *conf, int addressfamily)
|
||||
{
|
||||
static const struct plug_function_table fn_table = {
|
||||
pfd_log,
|
||||
pfd_closing,
|
||||
pfd_receive,
|
||||
pfd_sent,
|
||||
NULL
|
||||
};
|
||||
|
||||
SockAddr addr;
|
||||
const char *err;
|
||||
char *dummy_realhost;
|
||||
char *dummy_realhost = NULL;
|
||||
struct PortForwarding *pf;
|
||||
|
||||
/*
|
||||
@@ -452,15 +460,15 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
|
||||
* Open socket.
|
||||
*/
|
||||
pf = *pf_ret = new_portfwd_state();
|
||||
pf->fn = &fn_table;
|
||||
pf->plugvt = &PortForwarding_plugvt;
|
||||
pf->throttled = pf->throttle_override = 0;
|
||||
pf->ready = 1;
|
||||
pf->c = c;
|
||||
pf->backhandle = NULL; /* we shouldn't need this */
|
||||
pf->dynamic = 0;
|
||||
pf->socks_state = SOCKS_NONE;
|
||||
|
||||
pf->s = new_connection(addr, dummy_realhost, port,
|
||||
0, 1, 0, 0, (Plug) pf, conf);
|
||||
0, 1, 0, 0, &pf->plugvt, conf);
|
||||
sfree(dummy_realhost);
|
||||
if ((err = sk_socket_error(pf->s)) != NULL) {
|
||||
char *err_ret = dupstr(err);
|
||||
@@ -479,26 +487,19 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
|
||||
|
||||
static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
|
||||
{
|
||||
static const struct plug_function_table fn_table = {
|
||||
pfd_log,
|
||||
pfd_closing,
|
||||
pfd_receive,
|
||||
pfd_sent,
|
||||
NULL
|
||||
};
|
||||
struct PortForwarding *pf;
|
||||
struct PortListener *pl;
|
||||
Socket s;
|
||||
const char *err;
|
||||
|
||||
pl = (struct PortListener *)p;
|
||||
pl = FROMFIELD(p, struct PortListener, plugvt);
|
||||
pf = new_portfwd_state();
|
||||
pf->fn = &fn_table;
|
||||
pf->plugvt = &PortForwarding_plugvt;
|
||||
|
||||
pf->c = NULL;
|
||||
pf->backhandle = pl->backhandle;
|
||||
|
||||
pf->s = s = constructor(ctx, (Plug) pf);
|
||||
pf->s = s = constructor(ctx, &pf->plugvt);
|
||||
if ((err = sk_socket_error(s)) != NULL) {
|
||||
free_portfwd_state(pf);
|
||||
return err != NULL;
|
||||
@@ -507,12 +508,14 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
|
||||
pf->throttled = pf->throttle_override = 0;
|
||||
pf->ready = 0;
|
||||
|
||||
if (pl->dynamic) {
|
||||
pf->dynamic = 1;
|
||||
if (pl->is_dynamic) {
|
||||
pf->socks_state = SOCKS_INITIAL;
|
||||
pf->socksbuf = strbuf_new();
|
||||
pf->socksbuf_consumed = 0;
|
||||
pf->port = 0; /* "hostname" buffer is so far empty */
|
||||
sk_set_frozen(s, 0); /* we want to receive SOCKS _now_! */
|
||||
} else {
|
||||
pf->dynamic = 0;
|
||||
pf->socks_state = SOCKS_NONE;
|
||||
pf->hostname = dupstr(pl->hostname);
|
||||
pf->port = pl->port;
|
||||
pf->c = new_sock_channel(pl->backhandle, pf);
|
||||
@@ -529,6 +532,13 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const Plug_vtable PortListener_plugvt = {
|
||||
pfl_log,
|
||||
pfl_closing,
|
||||
NULL, /* recv */
|
||||
NULL, /* send */
|
||||
pfl_accepting
|
||||
};
|
||||
|
||||
/*
|
||||
* Add a new port-forwarding listener from srcaddr:port -> desthost:destport.
|
||||
@@ -540,14 +550,6 @@ char *pfl_listen(char *desthost, int destport, char *srcaddr,
|
||||
int port, void *backhandle, Conf *conf,
|
||||
struct PortListener **pl_ret, int address_family)
|
||||
{
|
||||
static const struct plug_function_table fn_table = {
|
||||
pfl_log,
|
||||
pfl_closing,
|
||||
NULL, /* recv */
|
||||
NULL, /* send */
|
||||
pfl_accepting
|
||||
};
|
||||
|
||||
const char *err;
|
||||
struct PortListener *pl;
|
||||
|
||||
@@ -555,16 +557,16 @@ char *pfl_listen(char *desthost, int destport, char *srcaddr,
|
||||
* Open socket.
|
||||
*/
|
||||
pl = *pl_ret = new_portlistener_state();
|
||||
pl->fn = &fn_table;
|
||||
pl->plugvt = &PortListener_plugvt;
|
||||
if (desthost) {
|
||||
pl->hostname = dupstr(desthost);
|
||||
pl->port = destport;
|
||||
pl->dynamic = 0;
|
||||
pl->is_dynamic = FALSE;
|
||||
} else
|
||||
pl->dynamic = 1;
|
||||
pl->is_dynamic = TRUE;
|
||||
pl->backhandle = backhandle;
|
||||
|
||||
pl->s = new_listener(srcaddr, port, (Plug) pl,
|
||||
pl->s = new_listener(srcaddr, port, &pl->plugvt,
|
||||
!conf_get_int(conf, CONF_lport_acceptall),
|
||||
conf, address_family);
|
||||
if ((err = sk_socket_error(pl->s)) != NULL) {
|
||||
@@ -620,7 +622,7 @@ void pfd_override_throttle(struct PortForwarding *pf, int enable)
|
||||
/*
|
||||
* Called to send data down the raw connection.
|
||||
*/
|
||||
int pfd_send(struct PortForwarding *pf, char *data, int len)
|
||||
int pfd_send(struct PortForwarding *pf, const void *data, int len)
|
||||
{
|
||||
if (pf == NULL)
|
||||
return 0;
|
||||
@@ -640,10 +642,11 @@ void pfd_confirm(struct PortForwarding *pf)
|
||||
pf->ready = 1;
|
||||
sk_set_frozen(pf->s, 0);
|
||||
sk_write(pf->s, NULL, 0);
|
||||
if (pf->buffer) {
|
||||
sshfwd_write(pf->c, pf->buffer, pf->buflen);
|
||||
sfree(pf->buffer);
|
||||
pf->buffer = NULL;
|
||||
if (pf->socksbuf) {
|
||||
sshfwd_write(pf->c, pf->socksbuf->u + pf->socksbuf_consumed,
|
||||
pf->socksbuf->len - pf->socksbuf_consumed);
|
||||
strbuf_free(pf->socksbuf);
|
||||
pf->socksbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
302
source/putty/proxy.c
vendored
302
source/putty/proxy.c
vendored
@@ -23,7 +23,7 @@
|
||||
* Call this when proxy negotiation is complete, so that this
|
||||
* socket can begin working normally.
|
||||
*/
|
||||
void proxy_activate (Proxy_Socket p)
|
||||
void proxy_activate (ProxySocket *p)
|
||||
{
|
||||
void *data;
|
||||
int len;
|
||||
@@ -73,14 +73,14 @@ void proxy_activate (Proxy_Socket p)
|
||||
* unfreezing the actual underlying socket.
|
||||
*/
|
||||
if (!p->freeze)
|
||||
sk_set_frozen((Socket)p, 0);
|
||||
sk_set_frozen(&p->sockvt, 0);
|
||||
}
|
||||
|
||||
/* basic proxy socket functions */
|
||||
|
||||
static Plug sk_proxy_plug (Socket s, Plug p)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);
|
||||
Plug ret = ps->plug;
|
||||
if (p)
|
||||
ps->plug = p;
|
||||
@@ -89,16 +89,16 @@ static Plug sk_proxy_plug (Socket s, Plug p)
|
||||
|
||||
static void sk_proxy_close (Socket s)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);
|
||||
|
||||
sk_close(ps->sub_socket);
|
||||
sk_addr_free(ps->remote_addr);
|
||||
sfree(ps);
|
||||
}
|
||||
|
||||
static int sk_proxy_write (Socket s, const char *data, int len)
|
||||
static int sk_proxy_write (Socket s, const void *data, int len)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
bufchain_add(&ps->pending_output_data, data, len);
|
||||
@@ -107,9 +107,9 @@ static int sk_proxy_write (Socket s, const char *data, int len)
|
||||
return sk_write(ps->sub_socket, data, len);
|
||||
}
|
||||
|
||||
static int sk_proxy_write_oob (Socket s, const char *data, int len)
|
||||
static int sk_proxy_write_oob (Socket s, const void *data, int len)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
bufchain_clear(&ps->pending_output_data);
|
||||
@@ -122,7 +122,7 @@ static int sk_proxy_write_oob (Socket s, const char *data, int len)
|
||||
|
||||
static void sk_proxy_write_eof (Socket s)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->pending_eof = 1;
|
||||
@@ -133,7 +133,7 @@ static void sk_proxy_write_eof (Socket s)
|
||||
|
||||
static void sk_proxy_flush (Socket s)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->pending_flush = 1;
|
||||
@@ -144,7 +144,7 @@ static void sk_proxy_flush (Socket s)
|
||||
|
||||
static void sk_proxy_set_frozen (Socket s, int is_frozen)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->freeze = is_frozen;
|
||||
@@ -183,7 +183,7 @@ static void sk_proxy_set_frozen (Socket s, int is_frozen)
|
||||
|
||||
static const char * sk_proxy_socket_error (Socket s)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);
|
||||
if (ps->error != NULL || ps->sub_socket == NULL) {
|
||||
return ps->error;
|
||||
}
|
||||
@@ -195,8 +195,7 @@ static const char * sk_proxy_socket_error (Socket s)
|
||||
static void plug_proxy_log(Plug plug, int type, SockAddr addr, int port,
|
||||
const char *error_msg, int error_code)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) plug;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
ProxySocket *ps = FROMFIELD(plug, ProxySocket, plugvt);
|
||||
|
||||
plug_log(ps->plug, type, addr, port, error_msg, error_code);
|
||||
}
|
||||
@@ -204,8 +203,7 @@ static void plug_proxy_log(Plug plug, int type, SockAddr addr, int port,
|
||||
static void plug_proxy_closing (Plug p, const char *error_msg,
|
||||
int error_code, int calling_back)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) p;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->closing_error_msg = error_msg;
|
||||
@@ -219,8 +217,7 @@ static void plug_proxy_closing (Plug p, const char *error_msg,
|
||||
|
||||
static void plug_proxy_receive (Plug p, int urgent, char *data, int len)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) p;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
/* we will lose the urgentness of this data, but since most,
|
||||
@@ -239,8 +236,7 @@ static void plug_proxy_receive (Plug p, int urgent, char *data, int len)
|
||||
|
||||
static void plug_proxy_sent (Plug p, int bufsize)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) p;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->sent_bufsize = bufsize;
|
||||
@@ -253,8 +249,7 @@ static void plug_proxy_sent (Plug p, int bufsize)
|
||||
static int plug_proxy_accepting(Plug p,
|
||||
accept_fn_t constructor, accept_ctx_t ctx)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) p;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt);
|
||||
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->accepting_constructor = constructor;
|
||||
@@ -401,36 +396,35 @@ SockAddr name_lookup(const char *host, int port, char **canonicalname,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct Socket_vtable ProxySocket_sockvt = {
|
||||
sk_proxy_plug,
|
||||
sk_proxy_close,
|
||||
sk_proxy_write,
|
||||
sk_proxy_write_oob,
|
||||
sk_proxy_write_eof,
|
||||
sk_proxy_flush,
|
||||
sk_proxy_set_frozen,
|
||||
sk_proxy_socket_error,
|
||||
NULL, /* peer_info */
|
||||
};
|
||||
|
||||
static const struct Plug_vtable ProxySocket_plugvt = {
|
||||
plug_proxy_log,
|
||||
plug_proxy_closing,
|
||||
plug_proxy_receive,
|
||||
plug_proxy_sent,
|
||||
plug_proxy_accepting
|
||||
};
|
||||
|
||||
Socket new_connection(SockAddr addr, const char *hostname,
|
||||
int port, int privport,
|
||||
int oobinline, int nodelay, int keepalive,
|
||||
Plug plug, Conf *conf)
|
||||
{
|
||||
static const struct socket_function_table socket_fn_table = {
|
||||
sk_proxy_plug,
|
||||
sk_proxy_close,
|
||||
sk_proxy_write,
|
||||
sk_proxy_write_oob,
|
||||
sk_proxy_write_eof,
|
||||
sk_proxy_flush,
|
||||
sk_proxy_set_frozen,
|
||||
sk_proxy_socket_error,
|
||||
NULL, /* peer_info */
|
||||
};
|
||||
|
||||
static const struct plug_function_table plug_fn_table = {
|
||||
plug_proxy_log,
|
||||
plug_proxy_closing,
|
||||
plug_proxy_receive,
|
||||
plug_proxy_sent,
|
||||
plug_proxy_accepting
|
||||
};
|
||||
|
||||
if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE &&
|
||||
proxy_for_destination(addr, hostname, port, conf))
|
||||
{
|
||||
Proxy_Socket ret;
|
||||
Proxy_Plug pplug;
|
||||
ProxySocket *ret;
|
||||
SockAddr proxy_addr;
|
||||
char *proxy_canonical_name;
|
||||
const char *proxy_type;
|
||||
@@ -443,8 +437,9 @@ Socket new_connection(SockAddr addr, const char *hostname,
|
||||
NULL)
|
||||
return sret;
|
||||
|
||||
ret = snew(struct Socket_proxy_tag);
|
||||
ret->fn = &socket_fn_table;
|
||||
ret = snew(ProxySocket);
|
||||
ret->sockvt = &ProxySocket_sockvt;
|
||||
ret->plugvt = &ProxySocket_plugvt;
|
||||
ret->conf = conf_copy(conf);
|
||||
ret->plug = plug;
|
||||
ret->remote_addr = addr; /* will need to be freed on close */
|
||||
@@ -478,7 +473,7 @@ Socket new_connection(SockAddr addr, const char *hostname,
|
||||
proxy_type = "Telnet";
|
||||
} else {
|
||||
ret->error = "Proxy error: Unknown proxy method";
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -491,12 +486,6 @@ Socket new_connection(SockAddr addr, const char *hostname,
|
||||
sfree(logmsg);
|
||||
}
|
||||
|
||||
/* create the proxy plug to map calls from the actual
|
||||
* socket into our proxy socket layer */
|
||||
pplug = snew(struct Plug_proxy_tag);
|
||||
pplug->fn = &plug_fn_table;
|
||||
pplug->proxy_socket = ret;
|
||||
|
||||
{
|
||||
char *logmsg = dns_log_msg(conf_get_str(conf, CONF_proxy_host),
|
||||
conf_get_int(conf, CONF_addressfamily),
|
||||
@@ -511,9 +500,8 @@ Socket new_connection(SockAddr addr, const char *hostname,
|
||||
conf_get_int(conf, CONF_addressfamily));
|
||||
if (sk_addr_error(proxy_addr) != NULL) {
|
||||
ret->error = "Proxy error: Unable to resolve proxy host name";
|
||||
sfree(pplug);
|
||||
sk_addr_free(proxy_addr);
|
||||
return (Socket)ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
sfree(proxy_canonical_name);
|
||||
|
||||
@@ -533,19 +521,19 @@ Socket new_connection(SockAddr addr, const char *hostname,
|
||||
ret->sub_socket = sk_new(proxy_addr,
|
||||
conf_get_int(conf, CONF_proxy_port),
|
||||
privport, oobinline,
|
||||
nodelay, keepalive, (Plug) pplug,
|
||||
nodelay, keepalive, &ret->plugvt,
|
||||
#ifdef MPEXT
|
||||
conf_get_int(conf, CONF_connect_timeout), conf_get_int(conf, CONF_sndbuf)
|
||||
#endif
|
||||
);
|
||||
if (sk_socket_error(ret->sub_socket) != NULL)
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
|
||||
/* start the proxy negotiation process... */
|
||||
sk_set_frozen(ret->sub_socket, 0);
|
||||
ret->negotiate(ret, PROXY_CHANGE_NEW);
|
||||
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
/* no proxy, so just return the direct socket */
|
||||
@@ -604,7 +592,7 @@ static int get_line_end (char * data, int len)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int proxy_http_negotiate (Proxy_Socket p, int change)
|
||||
int proxy_http_negotiate (ProxySocket *p, int change)
|
||||
{
|
||||
if (p->state == PROXY_STATE_NEW) {
|
||||
/* we are just beginning the proxy negotiate process,
|
||||
@@ -789,7 +777,7 @@ int proxy_http_negotiate (Proxy_Socket p, int change)
|
||||
*/
|
||||
|
||||
/* SOCKS version 4 */
|
||||
int proxy_socks4_negotiate (Proxy_Socket p, int change)
|
||||
int proxy_socks4_negotiate (ProxySocket *p, int change)
|
||||
{
|
||||
if (p->state == PROXY_CHANGE_NEW) {
|
||||
|
||||
@@ -803,47 +791,38 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change)
|
||||
* user ID (variable length, null terminated string)
|
||||
*/
|
||||
|
||||
int length, type, namelen;
|
||||
char *command, addr[4], hostname[512];
|
||||
char *username;
|
||||
strbuf *command = strbuf_new();
|
||||
char hostname[512];
|
||||
int write_hostname = FALSE;
|
||||
|
||||
type = sk_addrtype(p->remote_addr);
|
||||
if (type == ADDRTYPE_IPV6) {
|
||||
put_byte(command, 4); /* SOCKS version 4 */
|
||||
put_byte(command, 1); /* CONNECT command */
|
||||
put_uint16(command, p->remote_port);
|
||||
|
||||
switch (sk_addrtype(p->remote_addr)) {
|
||||
case ADDRTYPE_IPV4:
|
||||
{
|
||||
char addr[4];
|
||||
sk_addrcopy(p->remote_addr, addr);
|
||||
put_data(command, addr, 4);
|
||||
break;
|
||||
}
|
||||
case ADDRTYPE_NAME:
|
||||
sk_getaddr(p->remote_addr, hostname, lenof(hostname));
|
||||
put_uint32(command, 1);
|
||||
write_hostname = TRUE;
|
||||
break;
|
||||
case ADDRTYPE_IPV6:
|
||||
p->error = "Proxy error: SOCKS version 4 does not support IPv6";
|
||||
return 1;
|
||||
} else if (type == ADDRTYPE_IPV4) {
|
||||
namelen = 0;
|
||||
sk_addrcopy(p->remote_addr, addr);
|
||||
} else { /* type == ADDRTYPE_NAME */
|
||||
assert(type == ADDRTYPE_NAME);
|
||||
sk_getaddr(p->remote_addr, hostname, lenof(hostname));
|
||||
namelen = strlen(hostname) + 1; /* include the NUL */
|
||||
addr[0] = addr[1] = addr[2] = 0;
|
||||
addr[3] = 1;
|
||||
strbuf_free(command);
|
||||
return 1;
|
||||
}
|
||||
|
||||
username = conf_get_str(p->conf, CONF_proxy_username);
|
||||
length = strlen(username) + namelen + 9;
|
||||
command = snewn(length, char);
|
||||
strcpy(command + 8, username);
|
||||
|
||||
command[0] = 4; /* version 4 */
|
||||
command[1] = 1; /* CONNECT command */
|
||||
|
||||
/* port */
|
||||
command[2] = (char) (p->remote_port >> 8) & 0xff;
|
||||
command[3] = (char) p->remote_port & 0xff;
|
||||
|
||||
/* address */
|
||||
memcpy(command + 4, addr, 4);
|
||||
|
||||
/* hostname */
|
||||
memcpy(command + 8 + strlen(username) + 1,
|
||||
hostname, namelen);
|
||||
|
||||
sk_write(p->sub_socket, command, length);
|
||||
sfree(username);
|
||||
sfree(command);
|
||||
put_asciz(command, conf_get_str(p->conf, CONF_proxy_username));
|
||||
if (write_hostname)
|
||||
put_asciz(command, hostname);
|
||||
sk_write(p->sub_socket, command->s, command->len);
|
||||
strbuf_free(command);
|
||||
|
||||
p->state = 1;
|
||||
return 0;
|
||||
@@ -949,7 +928,7 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change)
|
||||
}
|
||||
|
||||
/* SOCKS version 5 */
|
||||
int proxy_socks5_negotiate (Proxy_Socket p, int change)
|
||||
int proxy_socks5_negotiate (ProxySocket *p, int change)
|
||||
{
|
||||
if (p->state == PROXY_CHANGE_NEW) {
|
||||
|
||||
@@ -964,26 +943,30 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
|
||||
* 0x03 = CHAP
|
||||
*/
|
||||
|
||||
char command[5];
|
||||
strbuf *command;
|
||||
char *username, *password;
|
||||
int len;
|
||||
int method_count_offset, methods_start;
|
||||
|
||||
command[0] = 5; /* version 5 */
|
||||
command = strbuf_new();
|
||||
put_byte(command, 5); /* SOCKS version 5 */
|
||||
username = conf_get_str(p->conf, CONF_proxy_username);
|
||||
password = conf_get_str(p->conf, CONF_proxy_password);
|
||||
|
||||
method_count_offset = command->len;
|
||||
put_byte(command, 0);
|
||||
methods_start = command->len;
|
||||
|
||||
put_byte(command, 0x00); /* no authentication */
|
||||
|
||||
if (username[0] || password[0]) {
|
||||
command[2] = 0x00; /* no authentication */
|
||||
len = 3;
|
||||
proxy_socks5_offerencryptedauth (command, &len);
|
||||
command[len++] = 0x02; /* username/password */
|
||||
command[1] = len - 2; /* Number of methods supported */
|
||||
} else {
|
||||
command[1] = 1; /* one methods supported: */
|
||||
command[2] = 0x00; /* no authentication */
|
||||
len = 3;
|
||||
proxy_socks5_offerencryptedauth(BinarySink_UPCAST(command));
|
||||
put_byte(command, 0x02); /* username/password */
|
||||
}
|
||||
|
||||
sk_write(p->sub_socket, command, len);
|
||||
command->u[method_count_offset] = command->len - methods_start;
|
||||
|
||||
sk_write(p->sub_socket, command->s, command->len);
|
||||
strbuf_free(command);
|
||||
|
||||
p->state = 1;
|
||||
return 0;
|
||||
@@ -1121,36 +1104,40 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
|
||||
* dest. port (2 bytes) [network order]
|
||||
*/
|
||||
|
||||
char command[512];
|
||||
int len;
|
||||
int type;
|
||||
strbuf *command = strbuf_new();
|
||||
put_byte(command, 5); /* SOCKS version 5 */
|
||||
put_byte(command, 1); /* CONNECT command */
|
||||
put_byte(command, 0x00); /* reserved byte */
|
||||
|
||||
type = sk_addrtype(p->remote_addr);
|
||||
if (type == ADDRTYPE_IPV4) {
|
||||
len = 10; /* 4 hdr + 4 addr + 2 trailer */
|
||||
command[3] = 1; /* IPv4 */
|
||||
sk_addrcopy(p->remote_addr, command+4);
|
||||
} else if (type == ADDRTYPE_IPV6) {
|
||||
len = 22; /* 4 hdr + 16 addr + 2 trailer */
|
||||
command[3] = 4; /* IPv6 */
|
||||
sk_addrcopy(p->remote_addr, command+4);
|
||||
} else {
|
||||
assert(type == ADDRTYPE_NAME);
|
||||
command[3] = 3;
|
||||
sk_getaddr(p->remote_addr, command+5, 256);
|
||||
command[4] = strlen(command+5);
|
||||
len = 7 + command[4]; /* 4 hdr, 1 len, N addr, 2 trailer */
|
||||
switch (sk_addrtype(p->remote_addr)) {
|
||||
case ADDRTYPE_IPV4:
|
||||
put_byte(command, 1); /* IPv4 */
|
||||
sk_addrcopy(p->remote_addr, strbuf_append(command, 4));
|
||||
break;
|
||||
case ADDRTYPE_IPV6:
|
||||
put_byte(command, 4); /* IPv6 */
|
||||
sk_addrcopy(p->remote_addr, strbuf_append(command, 16));
|
||||
break;
|
||||
case ADDRTYPE_NAME:
|
||||
{
|
||||
char hostname[512];
|
||||
put_byte(command, 3); /* domain name */
|
||||
sk_getaddr(p->remote_addr, hostname, lenof(hostname));
|
||||
if (!put_pstring(command, hostname)) {
|
||||
p->error = "Proxy error: SOCKS 5 cannot "
|
||||
"support host names longer than 255 chars";
|
||||
strbuf_free(command);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
command[0] = 5; /* version 5 */
|
||||
command[1] = 1; /* CONNECT command */
|
||||
command[2] = 0x00;
|
||||
put_uint16(command, p->remote_port);
|
||||
|
||||
/* port */
|
||||
command[len-2] = (char) (p->remote_port >> 8) & 0xff;
|
||||
command[len-1] = (char) p->remote_port & 0xff;
|
||||
sk_write(p->sub_socket, command->s, command->len);
|
||||
|
||||
sk_write(p->sub_socket, command, len);
|
||||
strbuf_free(command);
|
||||
|
||||
p->state = 3;
|
||||
return 1;
|
||||
@@ -1249,23 +1236,25 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
|
||||
}
|
||||
|
||||
if (p->state == 5) {
|
||||
char *username = conf_get_str(p->conf, CONF_proxy_username);
|
||||
char *password = conf_get_str(p->conf, CONF_proxy_password);
|
||||
const char *username = conf_get_str(p->conf, CONF_proxy_username);
|
||||
const char *password = conf_get_str(p->conf, CONF_proxy_password);
|
||||
if (username[0] || password[0]) {
|
||||
char userpwbuf[255 + 255 + 3];
|
||||
int ulen, plen;
|
||||
ulen = strlen(username);
|
||||
if (ulen > 255) ulen = 255;
|
||||
if (ulen < 1) ulen = 1;
|
||||
plen = strlen(password);
|
||||
if (plen > 255) plen = 255;
|
||||
if (plen < 1) plen = 1;
|
||||
userpwbuf[0] = 1; /* version number of subnegotiation */
|
||||
userpwbuf[1] = ulen;
|
||||
memcpy(userpwbuf+2, username, ulen);
|
||||
userpwbuf[ulen+2] = plen;
|
||||
memcpy(userpwbuf+ulen+3, password, plen);
|
||||
sk_write(p->sub_socket, userpwbuf, ulen + plen + 3);
|
||||
strbuf *auth = strbuf_new();
|
||||
put_byte(auth, 1); /* version number of subnegotiation */
|
||||
if (!put_pstring(auth, username)) {
|
||||
p->error = "Proxy error: SOCKS 5 authentication cannot "
|
||||
"support usernames longer than 255 chars";
|
||||
strbuf_free(auth);
|
||||
return 1;
|
||||
}
|
||||
if (!put_pstring(auth, password)) {
|
||||
p->error = "Proxy error: SOCKS 5 authentication cannot "
|
||||
"support passwords longer than 255 chars";
|
||||
strbuf_free(auth);
|
||||
return 1;
|
||||
}
|
||||
sk_write(p->sub_socket, auth->s, auth->len);
|
||||
strbuf_free(auth);
|
||||
p->state = 7;
|
||||
} else
|
||||
plug_closing(p->plug, "Proxy error: Server chose "
|
||||
@@ -1515,7 +1504,7 @@ char *format_telnet_command(SockAddr addr, int port, Conf *conf)
|
||||
#undef ENSURE
|
||||
}
|
||||
|
||||
int proxy_telnet_negotiate (Proxy_Socket p, int change)
|
||||
int proxy_telnet_negotiate (ProxySocket *p, int change)
|
||||
{
|
||||
if (p->state == PROXY_CHANGE_NEW) {
|
||||
char *formatted_cmd;
|
||||
@@ -1610,3 +1599,10 @@ int proxy_telnet_negotiate (Proxy_Socket p, int change)
|
||||
PROXY_ERROR_UNEXPECTED, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef MPEXT
|
||||
ProxySocket * get_proxy_plug_socket(Plug p)
|
||||
{
|
||||
return FROMFIELD(p, ProxySocket, plugvt);
|
||||
}
|
||||
#endif
|
||||
42
source/putty/proxy.h
vendored
42
source/putty/proxy.h
vendored
@@ -13,12 +13,9 @@
|
||||
#define PROXY_ERROR_GENERAL 8000
|
||||
#define PROXY_ERROR_UNEXPECTED 8001
|
||||
|
||||
typedef struct Socket_proxy_tag * Proxy_Socket;
|
||||
|
||||
struct Socket_proxy_tag {
|
||||
const struct socket_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
typedef struct ProxySocket ProxySocket;
|
||||
|
||||
struct ProxySocket {
|
||||
const char *error;
|
||||
|
||||
Socket sub_socket;
|
||||
@@ -58,7 +55,7 @@ struct Socket_proxy_tag {
|
||||
* and further the proxy negotiation process.
|
||||
*/
|
||||
|
||||
int (*negotiate) (Proxy_Socket /* this */, int /* change type */);
|
||||
int (*negotiate) (ProxySocket * /* this */, int /* change type */);
|
||||
|
||||
/* current arguments of plug handlers
|
||||
* (for use by proxy's negotiate function)
|
||||
@@ -89,24 +86,17 @@ struct Socket_proxy_tag {
|
||||
int chap_num_attributes_processed;
|
||||
int chap_current_attribute;
|
||||
int chap_current_datalen;
|
||||
|
||||
const Socket_vtable *sockvt;
|
||||
const Plug_vtable *plugvt;
|
||||
};
|
||||
|
||||
typedef struct Plug_proxy_tag * Proxy_Plug;
|
||||
extern void proxy_activate (ProxySocket *);
|
||||
|
||||
struct Plug_proxy_tag {
|
||||
const struct plug_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
|
||||
Proxy_Socket proxy_socket;
|
||||
|
||||
};
|
||||
|
||||
extern void proxy_activate (Proxy_Socket);
|
||||
|
||||
extern int proxy_http_negotiate (Proxy_Socket, int);
|
||||
extern int proxy_telnet_negotiate (Proxy_Socket, int);
|
||||
extern int proxy_socks4_negotiate (Proxy_Socket, int);
|
||||
extern int proxy_socks5_negotiate (Proxy_Socket, int);
|
||||
extern int proxy_http_negotiate (ProxySocket *, int);
|
||||
extern int proxy_telnet_negotiate (ProxySocket *, int);
|
||||
extern int proxy_socks4_negotiate (ProxySocket *, int);
|
||||
extern int proxy_socks5_negotiate (ProxySocket *, int);
|
||||
|
||||
/*
|
||||
* This may be reused by local-command proxies on individual
|
||||
@@ -118,8 +108,12 @@ char *format_telnet_command(SockAddr addr, int port, Conf *conf);
|
||||
* These are implemented in cproxy.c or nocproxy.c, depending on
|
||||
* whether encrypted proxy authentication is available.
|
||||
*/
|
||||
extern void proxy_socks5_offerencryptedauth(char *command, int *len);
|
||||
extern int proxy_socks5_handlechap (Proxy_Socket p);
|
||||
extern int proxy_socks5_selectchap(Proxy_Socket p);
|
||||
extern void proxy_socks5_offerencryptedauth(BinarySink *);
|
||||
extern int proxy_socks5_handlechap (ProxySocket *);
|
||||
extern int proxy_socks5_selectchap(ProxySocket *);
|
||||
|
||||
#ifdef MPEXT
|
||||
ProxySocket * get_proxy_plug_socket(Plug p);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
237
source/putty/putty.h
vendored
237
source/putty/putty.h
vendored
@@ -16,27 +16,31 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DONE_TYPEDEFS
|
||||
#define DONE_TYPEDEFS
|
||||
typedef struct conf_tag Conf;
|
||||
typedef struct backend_tag Backend;
|
||||
typedef struct terminal_tag Terminal;
|
||||
#endif
|
||||
|
||||
#include "defs.h"
|
||||
#include "puttyps.h"
|
||||
#include "network.h"
|
||||
#include "misc.h"
|
||||
#include "marshal.h"
|
||||
|
||||
/*
|
||||
* Fingerprints of the PGP master keys that can be used to establish a trust
|
||||
* path between an executable and other files.
|
||||
* We express various time intervals in unsigned long minutes, but may need to
|
||||
* clip some values so that the resulting number of ticks does not overflow an
|
||||
* integer value.
|
||||
*/
|
||||
#define PGP_MASTER_KEY_FP \
|
||||
#define MAX_TICK_MINS (INT_MAX / (60 * TICKSPERSEC))
|
||||
|
||||
/*
|
||||
* Fingerprints of the current and previous PGP master keys, to
|
||||
* establish a trust path between an executable and other files.
|
||||
*/
|
||||
#define PGP_MASTER_KEY_YEAR "2018"
|
||||
#define PGP_MASTER_KEY_DETAILS "RSA, 4096-bit"
|
||||
#define PGP_MASTER_KEY_FP \
|
||||
"24E1 B1C5 75EA 3C9F F752 A922 76BC 7FE4 EBFD 2D9E"
|
||||
#define PGP_PREV_MASTER_KEY_YEAR "2015"
|
||||
#define PGP_PREV_MASTER_KEY_DETAILS "RSA, 4096-bit"
|
||||
#define PGP_PREV_MASTER_KEY_FP \
|
||||
"440D E3B5 B7A1 CA85 B3CC 1718 AB58 5DC6 0467 6F7C"
|
||||
#define PGP_RSA_MASTER_KEY_FP \
|
||||
"8F 15 97 DA 25 30 AB 0D 88 D1 92 54 11 CF 0C 4C"
|
||||
#define PGP_DSA_MASTER_KEY_FP \
|
||||
"313C 3E76 4B74 C2C5 F2AE 83A8 4F5E 6DF5 6A93 B34E"
|
||||
|
||||
/* Three attribute types:
|
||||
* The ATTRs (normal attributes) are stored with the characters in
|
||||
@@ -104,15 +108,16 @@ typedef struct terminal_tag Terminal;
|
||||
*/
|
||||
#define UCSWIDE 0xDFFF
|
||||
|
||||
#define ATTR_NARROW 0x800000U
|
||||
#define ATTR_WIDE 0x400000U
|
||||
#define ATTR_BOLD 0x040000U
|
||||
#define ATTR_UNDER 0x080000U
|
||||
#define ATTR_REVERSE 0x100000U
|
||||
#define ATTR_BLINK 0x200000U
|
||||
#define ATTR_FGMASK 0x0001FFU
|
||||
#define ATTR_BGMASK 0x03FE00U
|
||||
#define ATTR_COLOURS 0x03FFFFU
|
||||
#define ATTR_NARROW 0x0800000U
|
||||
#define ATTR_WIDE 0x0400000U
|
||||
#define ATTR_BOLD 0x0040000U
|
||||
#define ATTR_UNDER 0x0080000U
|
||||
#define ATTR_REVERSE 0x0100000U
|
||||
#define ATTR_BLINK 0x0200000U
|
||||
#define ATTR_FGMASK 0x00001FFU
|
||||
#define ATTR_BGMASK 0x003FE00U
|
||||
#define ATTR_COLOURS 0x003FFFFU
|
||||
#define ATTR_DIM 0x1000000U
|
||||
#define ATTR_FGSHIFT 0
|
||||
#define ATTR_BGSHIFT 9
|
||||
|
||||
@@ -530,8 +535,6 @@ GLOBAL int loaded_session;
|
||||
*/
|
||||
GLOBAL char *cmdline_session_name;
|
||||
|
||||
struct RSAKey; /* be a little careful of scope */
|
||||
|
||||
/*
|
||||
* Mechanism for getting text strings such as usernames and passwords
|
||||
* from the front-end.
|
||||
@@ -592,12 +595,65 @@ void prompt_ensure_result_size(prompt_t *pr, int len);
|
||||
/* Burn the evidence. (Assumes _all_ strings want free()ing.) */
|
||||
void free_prompts(prompts_t *p);
|
||||
|
||||
/*
|
||||
* Data type definitions for true-colour terminal display.
|
||||
* 'optionalrgb' describes a single RGB colour, which overrides the
|
||||
* other colour settings if 'enabled' is nonzero, and is ignored
|
||||
* otherwise. 'truecolour' contains a pair of those for foreground and
|
||||
* background.
|
||||
*/
|
||||
typedef struct optionalrgb {
|
||||
unsigned char enabled;
|
||||
unsigned char r, g, b;
|
||||
} optionalrgb;
|
||||
extern const optionalrgb optionalrgb_none;
|
||||
typedef struct truecolour {
|
||||
optionalrgb fg, bg;
|
||||
} truecolour;
|
||||
#define optionalrgb_equal(r1,r2) ( \
|
||||
(r1).enabled==(r2).enabled && \
|
||||
(r1).r==(r2).r && (r1).g==(r2).g && (r1).b==(r2).b)
|
||||
#define truecolour_equal(c1,c2) ( \
|
||||
optionalrgb_equal((c1).fg, (c2).fg) && \
|
||||
optionalrgb_equal((c1).bg, (c2).bg))
|
||||
|
||||
/*
|
||||
* Enumeration of clipboards. We provide some standard ones cross-
|
||||
* platform, and then permit each platform to extend this enumeration
|
||||
* further by defining PLATFORM_CLIPBOARDS in its own header file.
|
||||
*
|
||||
* CLIP_NULL is a non-clipboard, writes to which are ignored and reads
|
||||
* from which return no data.
|
||||
*
|
||||
* CLIP_LOCAL refers to a buffer within terminal.c, which
|
||||
* unconditionally saves the last data selected in the terminal. In
|
||||
* configurations where a system clipboard is not written
|
||||
* automatically on selection but instead by an explicit UI action,
|
||||
* this is where the code responding to that action can find the data
|
||||
* to write to the clipboard in question.
|
||||
*/
|
||||
#define CROSS_PLATFORM_CLIPBOARDS(X) \
|
||||
X(CLIP_NULL, "null clipboard") \
|
||||
X(CLIP_LOCAL, "last text selected in terminal") \
|
||||
/* end of list */
|
||||
|
||||
#define ALL_CLIPBOARDS(X) \
|
||||
CROSS_PLATFORM_CLIPBOARDS(X) \
|
||||
PLATFORM_CLIPBOARDS(X) \
|
||||
/* end of list */
|
||||
|
||||
#define CLIP_ID(id,name) id,
|
||||
enum { ALL_CLIPBOARDS(CLIP_ID) N_CLIPBOARDS };
|
||||
#undef CLIP_ID
|
||||
|
||||
/*
|
||||
* Exports from the front end.
|
||||
*/
|
||||
void request_resize(void *frontend, int, int);
|
||||
void do_text(Context, int, int, wchar_t *, int, unsigned long, int);
|
||||
void do_cursor(Context, int, int, wchar_t *, int, unsigned long, int);
|
||||
void do_text(Context, int, int, wchar_t *, int, unsigned long, int,
|
||||
truecolour);
|
||||
void do_cursor(Context, int, int, wchar_t *, int, unsigned long, int,
|
||||
truecolour);
|
||||
int char_width(Context ctx, int uc);
|
||||
#ifdef OPTIMISE_SCROLL
|
||||
void do_scroll(Context, int, int, int);
|
||||
@@ -609,23 +665,21 @@ Context get_ctx(void *frontend);
|
||||
void free_ctx(Context);
|
||||
void palette_set(void *frontend, int, int, int, int);
|
||||
void palette_reset(void *frontend);
|
||||
void write_aclip(void *frontend, char *, int, int);
|
||||
void write_clip(void *frontend, wchar_t *, int *, int, int);
|
||||
void get_clip(void *frontend, wchar_t **, int *);
|
||||
int palette_get(void *frontend, int n, int *r, int *g, int *b);
|
||||
void write_clip(void *frontend, int clipboard, wchar_t *, int *,
|
||||
truecolour *, int, int);
|
||||
void optimised_move(void *frontend, int, int, int);
|
||||
void set_raw_mouse_mode(void *frontend, int);
|
||||
void connection_fatal(void *frontend, const char *, ...);
|
||||
void nonfatal(const char *, ...);
|
||||
void fatalbox(const char *, ...);
|
||||
void modalfatalbox(const char *, ...);
|
||||
#ifdef macintosh
|
||||
#pragma noreturn(fatalbox)
|
||||
#pragma noreturn(modalfatalbox)
|
||||
#endif
|
||||
void do_beep(void *frontend, int);
|
||||
void begin_session(void *frontend);
|
||||
void sys_cursor(void *frontend, int x, int y);
|
||||
void request_paste(void *frontend);
|
||||
void frontend_request_paste(void *frontend, int clipboard);
|
||||
void frontend_keypress(void *frontend);
|
||||
void frontend_echoedit_update(void *frontend, int echo, int edit);
|
||||
/* It's the backend's responsibility to invoke this at the start of a
|
||||
@@ -633,8 +687,8 @@ void frontend_echoedit_update(void *frontend, int echo, int edit);
|
||||
* special commands changes. It does not need to invoke it at session
|
||||
* shutdown. */
|
||||
void update_specials_menu(void *frontend);
|
||||
int from_backend(void *frontend, int is_stderr, const char *data, int len);
|
||||
int from_backend_untrusted(void *frontend, const char *data, int len);
|
||||
int from_backend(void *frontend, int is_stderr, const void *data, int len);
|
||||
int from_backend_untrusted(void *frontend, const void *data, int len);
|
||||
/* Called when the back end wants to indicate that EOF has arrived on
|
||||
* the server-to-client stream. Returns FALSE to indicate that we
|
||||
* intend to keep the session open in the other direction, or TRUE to
|
||||
@@ -647,9 +701,9 @@ char *get_ttymode(void *frontend, const char *mode);
|
||||
/*
|
||||
* >0 = `got all results, carry on'
|
||||
* 0 = `user cancelled' (FIXME distinguish "give up entirely" and "next auth"?)
|
||||
* <0 = `please call back later with more in/inlen'
|
||||
* <0 = `please call back later with a fuller bufchain'
|
||||
*/
|
||||
int get_userpass_input(prompts_t *p, const unsigned char *in, int inlen);
|
||||
int get_userpass_input(prompts_t *p, bufchain *input);
|
||||
#define OPTIMISE_IS_SCROLL 1
|
||||
|
||||
void set_iconic(void *frontend, int iconic);
|
||||
@@ -735,8 +789,10 @@ void cleanup_exit(int);
|
||||
X(INT, NONE, ssh_show_banner) /* show USERAUTH_BANNERs (SSH-2 only) */ \
|
||||
X(INT, NONE, try_tis_auth) \
|
||||
X(INT, NONE, try_ki_auth) \
|
||||
X(INT, NONE, try_gssapi_auth) /* attempt gssapi auth */ \
|
||||
X(INT, NONE, try_gssapi_auth) /* attempt gssapi auth via ssh userauth */ \
|
||||
X(INT, NONE, try_gssapi_kex) /* attempt gssapi auth via ssh kex */ \
|
||||
X(INT, NONE, gssapifwd) /* forward tgt via gss */ \
|
||||
X(INT, NONE, gssapirekey) /* KEXGSS refresh interval (mins) */ \
|
||||
X(INT, INT, ssh_gsslist) /* preference order for local GSS libs */ \
|
||||
X(FILENAME, NONE, ssh_gss_custom) \
|
||||
X(INT, NONE, ssh_subsys) /* run a subsystem rather than a command */ \
|
||||
@@ -835,6 +891,7 @@ void cleanup_exit(int);
|
||||
/* Colour options */ \
|
||||
X(INT, NONE, ansi_colour) \
|
||||
X(INT, NONE, xterm_256_colour) \
|
||||
X(INT, NONE, true_colour) \
|
||||
X(INT, NONE, system_colour) \
|
||||
X(INT, NONE, try_palette) \
|
||||
X(INT, NONE, bold_style) \
|
||||
@@ -842,10 +899,19 @@ void cleanup_exit(int);
|
||||
/* Selection options */ \
|
||||
X(INT, NONE, mouse_is_xterm) \
|
||||
X(INT, NONE, rect_select) \
|
||||
X(INT, NONE, paste_controls) \
|
||||
X(INT, NONE, rawcnp) \
|
||||
X(INT, NONE, utf8linedraw) \
|
||||
X(INT, NONE, rtf_paste) \
|
||||
X(INT, NONE, mouse_override) \
|
||||
X(INT, INT, wordness) \
|
||||
X(INT, NONE, mouseautocopy) \
|
||||
X(INT, NONE, mousepaste) \
|
||||
X(INT, NONE, ctrlshiftins) \
|
||||
X(INT, NONE, ctrlshiftcv) \
|
||||
X(STR, NONE, mousepaste_custom) \
|
||||
X(STR, NONE, ctrlshiftins_custom) \
|
||||
X(STR, NONE, ctrlshiftcv_custom) \
|
||||
/* translations */ \
|
||||
X(INT, NONE, vtmode) \
|
||||
X(STR, NONE, line_codepage) \
|
||||
@@ -956,9 +1022,8 @@ void conf_del_str_str(Conf *conf, int key, const char *subkey);
|
||||
void conf_set_filename(Conf *conf, int key, const Filename *val);
|
||||
void conf_set_fontspec(Conf *conf, int key, const FontSpec *val);
|
||||
/* Serialisation functions for Duplicate Session */
|
||||
int conf_serialised_size(Conf *conf);
|
||||
void conf_serialise(Conf *conf, void *data);
|
||||
int conf_deserialise(Conf *conf, void *data, int maxsize);/*returns size used*/
|
||||
void conf_serialise(BinarySink *bs, Conf *conf);
|
||||
int conf_deserialise(Conf *conf, BinarySource *src);/*returns true on success*/
|
||||
|
||||
/*
|
||||
* Functions to copy, free, serialise and deserialise FontSpecs.
|
||||
@@ -971,8 +1036,8 @@ int conf_deserialise(Conf *conf, void *data, int maxsize);/*returns size used*/
|
||||
*/
|
||||
FontSpec *fontspec_copy(const FontSpec *f);
|
||||
void fontspec_free(FontSpec *f);
|
||||
int fontspec_serialise(FontSpec *f, void *data);
|
||||
FontSpec *fontspec_deserialise(void *data, int maxsize, int *used);
|
||||
void fontspec_serialise(BinarySink *bs, FontSpec *f);
|
||||
FontSpec *fontspec_deserialise(BinarySource *src);
|
||||
|
||||
/*
|
||||
* Exports from noise.c.
|
||||
@@ -1034,26 +1099,27 @@ void term_mouse(Terminal *, Mouse_Button, Mouse_Button, Mouse_Action,
|
||||
int,int,int,int,int);
|
||||
void term_key(Terminal *, Key_Sym, wchar_t *, size_t, unsigned int,
|
||||
unsigned int);
|
||||
void term_deselect(Terminal *);
|
||||
void term_lost_clipboard_ownership(Terminal *, int clipboard);
|
||||
void term_update(Terminal *);
|
||||
void term_invalidate(Terminal *);
|
||||
void term_blink(Terminal *, int set_cursor);
|
||||
void term_do_paste(Terminal *);
|
||||
void term_do_paste(Terminal *, const wchar_t *, int);
|
||||
void term_nopaste(Terminal *);
|
||||
int term_ldisc(Terminal *, int option);
|
||||
void term_copyall(Terminal *);
|
||||
void term_copyall(Terminal *, const int *, int);
|
||||
void term_reconfig(Terminal *, Conf *);
|
||||
void term_seen_key_event(Terminal *);
|
||||
int term_data(Terminal *, int is_stderr, const char *data, int len);
|
||||
int term_data_untrusted(Terminal *, const char *data, int len);
|
||||
void term_request_copy(Terminal *, const int *clipboards, int n_clipboards);
|
||||
void term_request_paste(Terminal *, int clipboard);
|
||||
void term_seen_key_event(Terminal *);
|
||||
int term_data(Terminal *, int is_stderr, const void *data, int len);
|
||||
int term_data_untrusted(Terminal *, const void *data, int len);
|
||||
void term_provide_resize_fn(Terminal *term,
|
||||
void (*resize_fn)(void *, int, int),
|
||||
void *resize_ctx);
|
||||
void term_provide_logctx(Terminal *term, void *logctx);
|
||||
void term_set_focus(Terminal *term, int has_focus);
|
||||
char *term_get_ttymode(Terminal *term, const char *mode);
|
||||
int term_get_userpass_input(Terminal *term, prompts_t *p,
|
||||
const unsigned char *in, int inlen);
|
||||
int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input);
|
||||
|
||||
int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl);
|
||||
|
||||
@@ -1117,7 +1183,7 @@ extern Backend ssh_backend;
|
||||
void *ldisc_create(Conf *, Terminal *, Backend *, void *, void *);
|
||||
void ldisc_configure(void *, Conf *);
|
||||
void ldisc_free(void *);
|
||||
void ldisc_send(void *handle, const char *buf, int len, int interactive);
|
||||
void ldisc_send(void *handle, const void *buf, int len, int interactive);
|
||||
void ldisc_echoedit_update(void *handle);
|
||||
|
||||
/*
|
||||
@@ -1157,6 +1223,11 @@ void pinger_free(Pinger);
|
||||
int conf_launchable(Conf *conf);
|
||||
char const *conf_dest(Conf *conf);
|
||||
|
||||
/*
|
||||
* Exports from sessprep.c.
|
||||
*/
|
||||
void prepare_session(Conf *conf);
|
||||
|
||||
/*
|
||||
* Exports from sercfg.c.
|
||||
*/
|
||||
@@ -1196,14 +1267,6 @@ int mk_wcswidth(const unsigned int *pwcs, size_t n);
|
||||
int mk_wcwidth_cjk(unsigned int ucs);
|
||||
int mk_wcswidth_cjk(const unsigned int *pwcs, size_t n);
|
||||
|
||||
/*
|
||||
* Exports from mscrypto.c
|
||||
*/
|
||||
#ifdef MSCRYPTOAPI
|
||||
int crypto_startup();
|
||||
void crypto_wrapup();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Exports from pageantc.c.
|
||||
*
|
||||
@@ -1229,10 +1292,10 @@ void crypto_wrapup();
|
||||
*/
|
||||
typedef struct agent_pending_query agent_pending_query;
|
||||
agent_pending_query *agent_query(
|
||||
void *in, int inlen, void **out, int *outlen,
|
||||
strbuf *in, void **out, int *outlen,
|
||||
void (*callback)(void *, void *, int), void *callback_ctx);
|
||||
void agent_cancel_query(agent_pending_query *);
|
||||
void agent_query_synchronous(void *in, int inlen, void **out, int *outlen);
|
||||
void agent_query_synchronous(strbuf *in, void **out, int *outlen);
|
||||
int agent_exists(void);
|
||||
|
||||
/*
|
||||
@@ -1302,8 +1365,7 @@ void display_banner(void *frontend, const char* banner, int size);
|
||||
* that aren't equivalents to things in windlg.c et al.
|
||||
*/
|
||||
extern int console_batch_mode;
|
||||
int console_get_userpass_input(prompts_t *p, const unsigned char *in,
|
||||
int inlen);
|
||||
int console_get_userpass_input(prompts_t *p);
|
||||
void console_provide_logctx(void *logctx);
|
||||
int is_interactive(void);
|
||||
|
||||
@@ -1332,9 +1394,15 @@ void printer_finish_job(printer_job *);
|
||||
int cmdline_process_param(const char *, char *, int, Conf *);
|
||||
void cmdline_run_saved(Conf *);
|
||||
void cmdline_cleanup(void);
|
||||
int cmdline_get_passwd_input(prompts_t *p, const unsigned char *in, int inlen);
|
||||
int cmdline_get_passwd_input(prompts_t *p);
|
||||
int cmdline_host_ok(Conf *);
|
||||
#define TOOLTYPE_FILETRANSFER 1
|
||||
#define TOOLTYPE_NONNETWORK 2
|
||||
#define TOOLTYPE_HOST_ARG 4
|
||||
#define TOOLTYPE_HOST_ARG_CAN_BE_SESSION 8
|
||||
#define TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX 16
|
||||
#define TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD 32
|
||||
#define TOOLTYPE_PORT_ARG 64
|
||||
extern int cmdline_tooltype;
|
||||
|
||||
void cmdline_error(const char *, ...);
|
||||
@@ -1380,6 +1448,16 @@ enum {
|
||||
};
|
||||
extern const char *const x11_authnames[]; /* declared in x11fwd.c */
|
||||
|
||||
/*
|
||||
* An enum for the copy-paste UI action configuration.
|
||||
*/
|
||||
enum {
|
||||
CLIPUI_NONE, /* UI action has no copy/paste effect */
|
||||
CLIPUI_IMPLICIT, /* use the default clipboard implicit in mouse actions */
|
||||
CLIPUI_EXPLICIT, /* use the default clipboard for explicit Copy/Paste */
|
||||
CLIPUI_CUSTOM, /* use a named clipboard (on systems that support it) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Miscellaneous exports from the platform-specific code.
|
||||
*
|
||||
@@ -1392,11 +1470,12 @@ int filename_equal(const Filename *f1, const Filename *f2);
|
||||
int filename_is_null(const Filename *fn);
|
||||
Filename *filename_copy(const Filename *fn);
|
||||
void filename_free(Filename *fn);
|
||||
int filename_serialise(const Filename *f, void *data);
|
||||
Filename *filename_deserialise(void *data, int maxsize, int *used);
|
||||
void filename_serialise(BinarySink *bs, const Filename *f);
|
||||
Filename *filename_deserialise(BinarySource *src);
|
||||
char *get_username(void); /* return value needs freeing */
|
||||
char *get_random_data(int bytes, const char *device); /* used in cmdgen.c */
|
||||
char filename_char_sanitise(char c); /* rewrite special pathname chars */
|
||||
int open_for_write_would_lose_data(const Filename *fn);
|
||||
|
||||
/*
|
||||
* Exports and imports from timing.c.
|
||||
@@ -1515,11 +1594,33 @@ unsigned long timing_last_clock(void);
|
||||
* actually running it (e.g. so as to put a zero timeout on a select()
|
||||
* call) then it can call toplevel_callback_pending(), which will
|
||||
* return true if at least one callback is in the queue.
|
||||
*
|
||||
* run_toplevel_callbacks() returns TRUE if it ran any actual code.
|
||||
* This can be used as a means of speculatively terminating a select
|
||||
* loop, as in PSFTP, for example - if a callback has run then perhaps
|
||||
* it might have done whatever the loop's caller was waiting for.
|
||||
*/
|
||||
typedef void (*toplevel_callback_fn_t)(void *ctx);
|
||||
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx);
|
||||
void run_toplevel_callbacks(void);
|
||||
int run_toplevel_callbacks(void);
|
||||
int toplevel_callback_pending(void);
|
||||
void delete_callbacks_for_context(void *ctx);
|
||||
|
||||
/*
|
||||
* Another facility in callback.c deals with 'idempotent' callbacks,
|
||||
* defined as those which never need to be scheduled again if they are
|
||||
* already scheduled and have not yet run. (An example would be one
|
||||
* which, when called, empties a queue of data completely: when data
|
||||
* is added to the queue, you must ensure a run of the queue-consuming
|
||||
* function has been scheduled, but if one is already pending, you
|
||||
* don't need to schedule a second one.)
|
||||
*/
|
||||
struct IdempotentCallback {
|
||||
toplevel_callback_fn_t fn;
|
||||
void *ctx;
|
||||
int queued;
|
||||
};
|
||||
void queue_idempotent_callback(struct IdempotentCallback *ic);
|
||||
|
||||
typedef void (*toplevel_callback_notify_fn_t)(void *frontend);
|
||||
void request_callback_notifications(toplevel_callback_notify_fn_t notify,
|
||||
|
||||
12
source/putty/puttyexp.h
vendored
12
source/putty/puttyexp.h
vendored
@@ -1,28 +1,29 @@
|
||||
#ifndef PUTTY_PUTTYEXP_H
|
||||
#define PUTTY_PUTTYEXP_H
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
// from ssh.c
|
||||
|
||||
void ssh_close(void * handle);
|
||||
int is_ssh(void * handle);
|
||||
void call_ssh_timer(void * handle);
|
||||
int get_ssh_version(void * handle);
|
||||
void * get_ssh_frontend(void * handle);
|
||||
void * get_ssh_frontend(Plug plug);
|
||||
int get_ssh1_compressing(void * handle);
|
||||
const struct ssh_cipher * get_cipher(void * handle);
|
||||
const struct ssh2_cipher * get_cscipher(void * handle);
|
||||
const struct ssh2_cipher * get_sccipher(void * handle);
|
||||
const struct ssh_compress * get_cscomp(void * handle);
|
||||
const struct ssh_compress * get_sccomp(void * handle);
|
||||
int get_ssh_state(void * handle);
|
||||
int get_ssh_state_closed(void * handle);
|
||||
int get_ssh_state_session(void * handle);
|
||||
int get_ssh_exitcode(void * handle);
|
||||
const unsigned int * ssh2_remmaxpkt(void * handle);
|
||||
const unsigned int * ssh2_remwindow(void * handle);
|
||||
void md5checksum(const char * buffer, int len, unsigned char output[16]);
|
||||
typedef const struct ssh_signkey * cp_ssh_signkey;
|
||||
void get_hostkey_algs(int * count, cp_ssh_signkey * SignKeys);
|
||||
typedef const struct ssh_keyalg * cp_ssh_keyalg;
|
||||
void get_hostkey_algs(int * count, cp_ssh_keyalg * SignKeys);
|
||||
void get_macs(int * count, const struct ssh_mac *** amacs);
|
||||
|
||||
// from wingss.c
|
||||
@@ -66,11 +67,10 @@ extern const struct ssh_compress ssh_zlib;
|
||||
|
||||
void * call_aes_make_context();
|
||||
void call_aes_free_context(void * handle);
|
||||
void call_aes_setup(void * ctx, int blocklen, unsigned char * key, int keylen);
|
||||
void call_aes_setup(void * ctx, unsigned char * key, int keylen);
|
||||
void call_aes_encrypt(void * ctx, unsigned int * block);
|
||||
void call_aes_decrypt(void * ctx, unsigned int * block);
|
||||
void call_aes_sdctr(unsigned char *blk, int len, void *ctx);
|
||||
void aes_iv(void *handle, unsigned char *iv);
|
||||
|
||||
// from winmisc.c
|
||||
|
||||
|
||||
15
source/putty/puttymem.h
vendored
15
source/putty/puttymem.h
vendored
@@ -49,4 +49,19 @@ void safefree(void *);
|
||||
((type *)snrealloc(sizeof((type *)0 == (ptr)) ? (ptr) : (ptr), \
|
||||
(n), sizeof(type)))
|
||||
|
||||
/*
|
||||
* For cases where you want to allocate a struct plus a subsidiary
|
||||
* data buffer in one step, this macro lets you add a constant to the
|
||||
* amount malloced.
|
||||
*
|
||||
* Since the return value is already cast to the struct type, a
|
||||
* pointer to that many bytes of extra data can be conveniently
|
||||
* obtained by simply adding 1 to the returned pointer!
|
||||
* snew_plus_get_aux is a handy macro that does that and casts the
|
||||
* result to void *, so you can assign it straight to wherever you
|
||||
* wanted it.
|
||||
*/
|
||||
#define snew_plus(type, extra) ((type *)snmalloc(1, sizeof(type) + (extra)))
|
||||
#define snew_plus_get_aux(ptr) ((void *)((ptr) + 1))
|
||||
|
||||
#endif
|
||||
|
||||
7603
source/putty/ssh.c
vendored
7603
source/putty/ssh.c
vendored
File diff suppressed because it is too large
Load Diff
505
source/putty/ssh.h
vendored
505
source/putty/ssh.h
vendored
@@ -1,17 +1,19 @@
|
||||
#ifndef WINSCP_VS
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "puttymem.h"
|
||||
#include "tree234.h"
|
||||
#ifndef WINSCP_VS
|
||||
#include "network.h"
|
||||
#endif
|
||||
#include "int64.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
struct ssh_channel;
|
||||
typedef struct ssh_tag *Ssh;
|
||||
|
||||
extern int sshfwd_write(struct ssh_channel *c, char *, int);
|
||||
extern int sshfwd_write(struct ssh_channel *c, const void *, int);
|
||||
extern void sshfwd_write_eof(struct ssh_channel *c);
|
||||
extern void sshfwd_unclean_close(struct ssh_channel *c, const char *err);
|
||||
extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize);
|
||||
@@ -23,11 +25,139 @@ void sshfwd_x11_sharing_handover(struct ssh_channel *c,
|
||||
const void *initial_data, int initial_len);
|
||||
void sshfwd_x11_is_local(struct ssh_channel *c);
|
||||
|
||||
extern Socket ssh_connection_sharing_init(const char *host, int port,
|
||||
Conf *conf, Ssh ssh, void **state);
|
||||
/*
|
||||
* Buffer management constants. There are several of these for
|
||||
* various different purposes:
|
||||
*
|
||||
* - SSH1_BUFFER_LIMIT is the amount of backlog that must build up
|
||||
* on a local data stream before we throttle the whole SSH
|
||||
* connection (in SSH-1 only). Throttling the whole connection is
|
||||
* pretty drastic so we set this high in the hope it won't
|
||||
* happen very often.
|
||||
*
|
||||
* - SSH_MAX_BACKLOG is the amount of backlog that must build up
|
||||
* on the SSH connection itself before we defensively throttle
|
||||
* _all_ local data streams. This is pretty drastic too (though
|
||||
* thankfully unlikely in SSH-2 since the window mechanism should
|
||||
* ensure that the server never has any need to throttle its end
|
||||
* of the connection), so we set this high as well.
|
||||
*
|
||||
* - OUR_V2_WINSIZE is the default window size we present on SSH-2
|
||||
* channels.
|
||||
*
|
||||
* - OUR_V2_BIGWIN is the window size we advertise for the only
|
||||
* channel in a simple connection. It must be <= INT_MAX.
|
||||
*
|
||||
* - OUR_V2_MAXPKT is the official "maximum packet size" we send
|
||||
* to the remote side. This actually has nothing to do with the
|
||||
* size of the _packet_, but is instead a limit on the amount
|
||||
* of data we're willing to receive in a single SSH2 channel
|
||||
* data message.
|
||||
*
|
||||
* - OUR_V2_PACKETLIMIT is actually the maximum size of SSH
|
||||
* _packet_ we're prepared to cope with. It must be a multiple
|
||||
* of the cipher block size, and must be at least 35000.
|
||||
*/
|
||||
|
||||
#define SSH1_BUFFER_LIMIT 32768
|
||||
#define SSH_MAX_BACKLOG 32768
|
||||
#define OUR_V2_WINSIZE 16384
|
||||
#define OUR_V2_BIGWIN 0x7fffffff
|
||||
#define OUR_V2_MAXPKT 0x4000UL
|
||||
#define OUR_V2_PACKETLIMIT 0x9000UL
|
||||
|
||||
typedef struct PacketQueueNode PacketQueueNode;
|
||||
struct PacketQueueNode {
|
||||
PacketQueueNode *next, *prev;
|
||||
};
|
||||
|
||||
typedef struct PktIn {
|
||||
int refcount;
|
||||
int type;
|
||||
unsigned long sequence; /* SSH-2 incoming sequence number */
|
||||
long encrypted_len; /* for SSH-2 total-size counting */
|
||||
PacketQueueNode qnode; /* for linking this packet on to a queue */
|
||||
BinarySource_IMPLEMENTATION;
|
||||
} PktIn;
|
||||
|
||||
#endif
|
||||
typedef struct PktOut {
|
||||
long prefix; /* bytes up to and including type field */
|
||||
long length; /* total bytes, including prefix */
|
||||
int type;
|
||||
long minlen; /* SSH-2: ensure wire length is at least this */
|
||||
unsigned char *data; /* allocated storage */
|
||||
long maxlen; /* amount of storage allocated for `data' */
|
||||
long encrypted_len; /* for SSH-2 total-size counting */
|
||||
|
||||
/* Extra metadata used in SSH packet logging mode, allowing us to
|
||||
* log in the packet header line that the packet came from a
|
||||
* connection-sharing downstream and what if anything unusual was
|
||||
* done to it. The additional_log_text field is expected to be a
|
||||
* static string - it will not be freed. */
|
||||
unsigned downstream_id;
|
||||
const char *additional_log_text;
|
||||
|
||||
BinarySink_IMPLEMENTATION;
|
||||
} PktOut;
|
||||
#ifndef WINSCP_VS
|
||||
|
||||
typedef struct PacketQueue {
|
||||
PacketQueueNode end;
|
||||
} PacketQueue;
|
||||
|
||||
void pq_init(struct PacketQueue *pq);
|
||||
void pq_push(struct PacketQueue *pq, PktIn *pkt);
|
||||
void pq_push_front(struct PacketQueue *pq, PktIn *pkt);
|
||||
PktIn *pq_peek(struct PacketQueue *pq);
|
||||
PktIn *pq_pop(struct PacketQueue *pq);
|
||||
void pq_clear(struct PacketQueue *pq);
|
||||
int pq_empty_on_to_front_of(struct PacketQueue *src, struct PacketQueue *dest);
|
||||
|
||||
/*
|
||||
* Packet type contexts, so that ssh2_pkt_type can correctly decode
|
||||
* the ambiguous type numbers back into the correct type strings.
|
||||
*/
|
||||
typedef enum {
|
||||
SSH2_PKTCTX_NOKEX,
|
||||
SSH2_PKTCTX_DHGROUP,
|
||||
SSH2_PKTCTX_DHGEX,
|
||||
SSH2_PKTCTX_ECDHKEX,
|
||||
SSH2_PKTCTX_GSSKEX,
|
||||
SSH2_PKTCTX_RSAKEX
|
||||
} Pkt_KCtx;
|
||||
typedef enum {
|
||||
SSH2_PKTCTX_NOAUTH,
|
||||
SSH2_PKTCTX_PUBLICKEY,
|
||||
SSH2_PKTCTX_PASSWORD,
|
||||
SSH2_PKTCTX_GSSAPI,
|
||||
SSH2_PKTCTX_KBDINTER
|
||||
} Pkt_ACtx;
|
||||
|
||||
typedef struct PacketLogSettings {
|
||||
int omit_passwords, omit_data;
|
||||
Pkt_KCtx kctx;
|
||||
Pkt_ACtx actx;
|
||||
} PacketLogSettings;
|
||||
|
||||
#define MAX_BLANKS 4 /* no packet needs more censored sections than this */
|
||||
int ssh1_censor_packet(
|
||||
const PacketLogSettings *pls, int type, int sender_is_client,
|
||||
ptrlen pkt, logblank_t *blanks);
|
||||
int ssh2_censor_packet(
|
||||
const PacketLogSettings *pls, int type, int sender_is_client,
|
||||
ptrlen pkt, logblank_t *blanks);
|
||||
|
||||
PktOut *ssh_new_packet(void);
|
||||
void ssh_unref_packet(PktIn *pkt);
|
||||
void ssh_free_pktout(PktOut *pkt);
|
||||
|
||||
extern Socket ssh_connection_sharing_init(
|
||||
const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug,
|
||||
void **state);
|
||||
int ssh_share_test_for_upstream(const char *host, int port, Conf *conf);
|
||||
void share_got_pkt_from_server(void *ctx, int type,
|
||||
unsigned char *pkt, int pktlen);
|
||||
const void *pkt, int pktlen);
|
||||
void share_activate(void *state, const char *server_verstring);
|
||||
void sharestate_free(void *state);
|
||||
int share_ndownstreams(void *state);
|
||||
@@ -38,6 +168,8 @@ unsigned ssh_alloc_sharing_channel(Ssh ssh, void *sharing_ctx);
|
||||
void ssh_delete_sharing_channel(Ssh ssh, unsigned localid);
|
||||
int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
|
||||
void *share_ctx);
|
||||
void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
|
||||
void *share_ctx);
|
||||
void ssh_sharing_queue_global_request(Ssh ssh, void *share_ctx);
|
||||
struct X11FakeAuth *ssh_sharing_add_x11_display(Ssh ssh, int authtype,
|
||||
void *share_cs,
|
||||
@@ -71,35 +203,29 @@ void share_setup_x11_channel(void *csv, void *chanv,
|
||||
#define SSH_CIPHER_3DES 3
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
|
||||
#ifdef MSCRYPTOAPI
|
||||
#define APIEXTRA 8
|
||||
#else
|
||||
#define APIEXTRA 0
|
||||
#endif
|
||||
|
||||
#ifndef BIGNUM_INTERNAL
|
||||
typedef void *Bignum;
|
||||
#endif
|
||||
|
||||
typedef struct ssh_keyalg ssh_keyalg;
|
||||
typedef const struct ssh_keyalg *ssh_key;
|
||||
|
||||
struct RSAKey {
|
||||
int bits;
|
||||
int bytes;
|
||||
#ifdef MSCRYPTOAPI
|
||||
unsigned long exponent;
|
||||
unsigned char *modulus;
|
||||
#else
|
||||
Bignum modulus;
|
||||
Bignum exponent;
|
||||
Bignum private_exponent;
|
||||
Bignum p;
|
||||
Bignum q;
|
||||
Bignum iqmp;
|
||||
#endif
|
||||
char *comment;
|
||||
ssh_key sshk;
|
||||
};
|
||||
|
||||
struct dss_key {
|
||||
Bignum p, q, g, y, x;
|
||||
ssh_key sshk;
|
||||
};
|
||||
|
||||
struct ec_curve;
|
||||
@@ -153,48 +279,52 @@ struct ec_curve {
|
||||
};
|
||||
};
|
||||
|
||||
const struct ssh_signkey *ec_alg_by_oid(int len, const void *oid,
|
||||
const ssh_keyalg *ec_alg_by_oid(int len, const void *oid,
|
||||
const struct ec_curve **curve);
|
||||
const unsigned char *ec_alg_oid(const struct ssh_signkey *alg, int *oidlen);
|
||||
const unsigned char *ec_alg_oid(const ssh_keyalg *alg, int *oidlen);
|
||||
extern const int ec_nist_curve_lengths[], n_ec_nist_curve_lengths;
|
||||
int ec_nist_alg_and_curve_by_bits(int bits,
|
||||
const struct ec_curve **curve,
|
||||
const struct ssh_signkey **alg);
|
||||
const ssh_keyalg **alg);
|
||||
int ec_ed_alg_and_curve_by_bits(int bits,
|
||||
const struct ec_curve **curve,
|
||||
const struct ssh_signkey **alg);
|
||||
|
||||
struct ssh_signkey;
|
||||
const ssh_keyalg **alg);
|
||||
|
||||
struct ec_key {
|
||||
const struct ssh_signkey *signalg;
|
||||
struct ec_point publicKey;
|
||||
Bignum privateKey;
|
||||
ssh_key sshk;
|
||||
};
|
||||
|
||||
struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve);
|
||||
|
||||
int makekey(const unsigned char *data, int len, struct RSAKey *result,
|
||||
const unsigned char **keystr, int order);
|
||||
int makeprivate(const unsigned char *data, int len, struct RSAKey *result);
|
||||
int rsaencrypt(unsigned char *data, int length, struct RSAKey *key);
|
||||
Bignum rsadecrypt(Bignum input, struct RSAKey *key);
|
||||
void rsasign(unsigned char *data, int length, struct RSAKey *key);
|
||||
/*
|
||||
* SSH-1 never quite decided which order to store the two components
|
||||
* of an RSA key. During connection setup, the server sends its host
|
||||
* and server keys with the exponent first; private key files store
|
||||
* the modulus first. The agent protocol is even more confusing,
|
||||
* because the client specifies a key to the server in one order and
|
||||
* the server lists the keys it knows about in the other order!
|
||||
*/
|
||||
typedef enum { RSA_SSH1_EXPONENT_FIRST, RSA_SSH1_MODULUS_FIRST } RsaSsh1Order;
|
||||
|
||||
void BinarySource_get_rsa_ssh1_pub(
|
||||
BinarySource *src, struct RSAKey *result, RsaSsh1Order order);
|
||||
void BinarySource_get_rsa_ssh1_priv(
|
||||
BinarySource *src, struct RSAKey *rsa);
|
||||
int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key);
|
||||
Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key);
|
||||
void rsasanitise(struct RSAKey *key);
|
||||
int rsastr_len(struct RSAKey *key);
|
||||
void rsastr_fmt(char *str, struct RSAKey *key);
|
||||
void rsa_fingerprint(char *str, int len, struct RSAKey *key);
|
||||
char *rsa_ssh1_fingerprint(struct RSAKey *key);
|
||||
int rsa_verify(struct RSAKey *key);
|
||||
unsigned char *rsa_public_blob(struct RSAKey *key, int *len);
|
||||
int rsa_public_blob_len(void *data, int maxlen);
|
||||
void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
|
||||
RsaSsh1Order order);
|
||||
int rsa_ssh1_public_blob_len(void *data, int maxlen);
|
||||
void freersakey(struct RSAKey *key);
|
||||
#endif // WINSCP_VS
|
||||
|
||||
#ifndef PUTTY_UINT32_DEFINED
|
||||
/* This makes assumptions about the int type. */
|
||||
typedef unsigned int uint32;
|
||||
#define PUTTY_UINT32_DEFINED
|
||||
#endif
|
||||
typedef uint32 word32;
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
@@ -211,25 +341,22 @@ int detect_attack(void *handle, unsigned char *buf, uint32 len,
|
||||
* SSH2 RSA key exchange functions
|
||||
*/
|
||||
struct ssh_hash;
|
||||
struct ssh_rsa_kex_extra {
|
||||
int minklen;
|
||||
};
|
||||
void *ssh_rsakex_newkey(char *data, int len);
|
||||
void ssh_rsakex_freekey(void *key);
|
||||
int ssh_rsakex_klen(void *key);
|
||||
struct RSAKey *ssh_rsakex_newkey(const void *data, int len);
|
||||
void ssh_rsakex_freekey(struct RSAKey *key);
|
||||
int ssh_rsakex_klen(struct RSAKey *key);
|
||||
void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen,
|
||||
unsigned char *out, int outlen,
|
||||
void *key);
|
||||
unsigned char *out, int outlen, struct RSAKey *key);
|
||||
|
||||
/*
|
||||
* SSH2 ECDH key exchange functions
|
||||
*/
|
||||
struct ssh_kex;
|
||||
const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex);
|
||||
void *ssh_ecdhkex_newkey(const struct ssh_kex *kex);
|
||||
void ssh_ecdhkex_freekey(void *key);
|
||||
char *ssh_ecdhkex_getpublic(void *key, int *len);
|
||||
Bignum ssh_ecdhkex_getkey(void *key, char *remoteKey, int remoteKeyLen);
|
||||
struct ec_key *ssh_ecdhkex_newkey(const struct ssh_kex *kex);
|
||||
void ssh_ecdhkex_freekey(struct ec_key *key);
|
||||
void ssh_ecdhkex_getpublic(struct ec_key *key, BinarySink *bs);
|
||||
Bignum ssh_ecdhkex_getkey(struct ec_key *key,
|
||||
const void *remoteKey, int remoteKeyLen);
|
||||
|
||||
/*
|
||||
* Helper function for k generation in DSA, reused in ECDSA
|
||||
@@ -242,19 +369,14 @@ typedef struct {
|
||||
} MD5_Core_State;
|
||||
|
||||
struct MD5Context {
|
||||
#ifdef MSCRYPTOAPI
|
||||
unsigned long hHash;
|
||||
#else
|
||||
MD5_Core_State core;
|
||||
unsigned char block[64];
|
||||
int blkused;
|
||||
uint32 lenhi, lenlo;
|
||||
#endif
|
||||
BinarySink_IMPLEMENTATION;
|
||||
};
|
||||
|
||||
void MD5Init(struct MD5Context *context);
|
||||
void MD5Update(struct MD5Context *context, unsigned char const *buf,
|
||||
unsigned len);
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||
void MD5Simple(void const *p, unsigned len, unsigned char output[16]);
|
||||
|
||||
@@ -264,6 +386,8 @@ void hmacmd5_key(void *handle, void const *key, int len);
|
||||
void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len,
|
||||
unsigned char *hmac);
|
||||
|
||||
int supports_sha_ni(void);
|
||||
|
||||
#ifdef MPEXT
|
||||
// Resolve ambiguity with OpenSSL
|
||||
#define SHA_Init putty_SHA_Init
|
||||
@@ -274,29 +398,31 @@ void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len,
|
||||
#define SHA512_Final putty_SHA512_Final
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
typedef struct SHA_State {
|
||||
uint32 h[5];
|
||||
unsigned char block[64];
|
||||
int blkused;
|
||||
uint32 lenhi, lenlo;
|
||||
void (*sha1)(struct SHA_State * s, const unsigned char *p, int len);
|
||||
BinarySink_IMPLEMENTATION;
|
||||
} SHA_State;
|
||||
void SHA_Init(SHA_State * s);
|
||||
void SHA_Bytes(SHA_State * s, const void *p, int len);
|
||||
void SHA_Final(SHA_State * s, unsigned char *output);
|
||||
void SHA_Simple(const void *p, int len, unsigned char *output);
|
||||
|
||||
void hmac_sha1_simple(void *key, int keylen, void *data, int datalen,
|
||||
unsigned char *output);
|
||||
#endif // WINSCP_VS
|
||||
typedef struct {
|
||||
typedef struct SHA256_State {
|
||||
uint32 h[8];
|
||||
unsigned char block[64];
|
||||
int blkused;
|
||||
uint32 lenhi, lenlo;
|
||||
void (*sha256)(struct SHA256_State * s, const unsigned char *p, int len);
|
||||
BinarySink_IMPLEMENTATION;
|
||||
} SHA256_State;
|
||||
#ifndef WINSCP_VS
|
||||
void SHA256_Init(SHA256_State * s);
|
||||
void SHA256_Bytes(SHA256_State * s, const void *p, int len);
|
||||
void SHA256_Final(SHA256_State * s, unsigned char *output);
|
||||
void SHA256_Simple(const void *p, int len, unsigned char *output);
|
||||
|
||||
@@ -305,14 +431,13 @@ typedef struct {
|
||||
unsigned char block[128];
|
||||
int blkused;
|
||||
uint32 len[4];
|
||||
BinarySink_IMPLEMENTATION;
|
||||
} SHA512_State;
|
||||
#define SHA384_State SHA512_State
|
||||
void SHA512_Init(SHA512_State * s);
|
||||
void SHA512_Bytes(SHA512_State * s, const void *p, int len);
|
||||
void SHA512_Final(SHA512_State * s, unsigned char *output);
|
||||
void SHA512_Simple(const void *p, int len, unsigned char *output);
|
||||
void SHA384_Init(SHA384_State * s);
|
||||
#define SHA384_Bytes(s, p, len) SHA512_Bytes(s, p, len)
|
||||
void SHA384_Final(SHA384_State * s, unsigned char *output);
|
||||
void SHA384_Simple(const void *p, int len, unsigned char *output);
|
||||
|
||||
@@ -320,9 +445,9 @@ struct ssh_mac;
|
||||
struct ssh_cipher {
|
||||
void *(*make_context)(void);
|
||||
void (*free_context)(void *);
|
||||
void (*sesskey) (void *, unsigned char *key); /* for SSH-1 */
|
||||
void (*encrypt) (void *, unsigned char *blk, int len);
|
||||
void (*decrypt) (void *, unsigned char *blk, int len);
|
||||
void (*sesskey) (void *, const void *key); /* for SSH-1 */
|
||||
void (*encrypt) (void *, void *blk, int len);
|
||||
void (*decrypt) (void *, void *blk, int len);
|
||||
int blksize;
|
||||
const char *text_name;
|
||||
};
|
||||
@@ -330,13 +455,13 @@ struct ssh_cipher {
|
||||
struct ssh2_cipher {
|
||||
void *(*make_context)(void);
|
||||
void (*free_context)(void *);
|
||||
void (*setiv) (void *, unsigned char *key); /* for SSH-2 */
|
||||
void (*setkey) (void *, unsigned char *key);/* for SSH-2 */
|
||||
void (*encrypt) (void *, unsigned char *blk, int len);
|
||||
void (*decrypt) (void *, unsigned char *blk, int len);
|
||||
void (*setiv) (void *, const void *iv); /* for SSH-2 */
|
||||
void (*setkey) (void *, const void *key);/* for SSH-2 */
|
||||
void (*encrypt) (void *, void *blk, int len);
|
||||
void (*decrypt) (void *, void *blk, int len);
|
||||
/* Ignored unless SSH_CIPHER_SEPARATE_LENGTH flag set */
|
||||
void (*encrypt_length) (void *, unsigned char *blk, int len, unsigned long seq);
|
||||
void (*decrypt_length) (void *, unsigned char *blk, int len, unsigned long seq);
|
||||
void (*encrypt_length) (void *, void *blk, int len, unsigned long seq);
|
||||
void (*decrypt_length) (void *, void *blk, int len, unsigned long seq);
|
||||
const char *name;
|
||||
int blksize;
|
||||
/* real_keybits is the number of bits of entropy genuinely used by
|
||||
@@ -369,13 +494,13 @@ struct ssh_mac {
|
||||
/* Passes in the cipher context */
|
||||
void *(*make_context)(void *);
|
||||
void (*free_context)(void *);
|
||||
void (*setkey) (void *, unsigned char *key);
|
||||
void (*setkey) (void *, const void *key);
|
||||
/* whole-packet operations */
|
||||
void (*generate) (void *, unsigned char *blk, int len, unsigned long seq);
|
||||
int (*verify) (void *, unsigned char *blk, int len, unsigned long seq);
|
||||
void (*generate) (void *, void *blk, int len, unsigned long seq);
|
||||
int (*verify) (void *, const void *blk, int len, unsigned long seq);
|
||||
/* partial-packet operations */
|
||||
void (*start) (void *);
|
||||
void (*bytes) (void *, unsigned char const *, int);
|
||||
BinarySink *(*sink) (void *);
|
||||
void (*genresult) (void *, unsigned char *);
|
||||
int (*verresult) (void *, unsigned char const *);
|
||||
const char *name, *etm_name;
|
||||
@@ -386,7 +511,7 @@ struct ssh_mac {
|
||||
struct ssh_hash {
|
||||
void *(*init)(void); /* also allocates context */
|
||||
void *(*copy)(const void *);
|
||||
void (*bytes)(void *, const void *, int);
|
||||
BinarySink *(*sink) (void *);
|
||||
void (*final)(void *, unsigned char *); /* also frees context */
|
||||
void (*free)(void *);
|
||||
int hlen; /* output length in bytes */
|
||||
@@ -395,7 +520,7 @@ struct ssh_hash {
|
||||
|
||||
struct ssh_kex {
|
||||
const char *name, *groupname;
|
||||
enum { KEXTYPE_DH, KEXTYPE_RSA, KEXTYPE_ECDH } main_type;
|
||||
enum { KEXTYPE_DH, KEXTYPE_RSA, KEXTYPE_ECDH, KEXTYPE_GSS } main_type;
|
||||
const struct ssh_hash *hash;
|
||||
const void *extra; /* private to the kex methods */
|
||||
};
|
||||
@@ -405,39 +530,48 @@ struct ssh_kexes {
|
||||
const struct ssh_kex *const *list;
|
||||
};
|
||||
|
||||
struct ssh_signkey {
|
||||
void *(*newkey) (const struct ssh_signkey *self,
|
||||
const char *data, int len);
|
||||
void (*freekey) (void *key);
|
||||
char *(*fmtkey) (void *key);
|
||||
unsigned char *(*public_blob) (void *key, int *len);
|
||||
unsigned char *(*private_blob) (void *key, int *len);
|
||||
void *(*createkey) (const struct ssh_signkey *self,
|
||||
const unsigned char *pub_blob, int pub_len,
|
||||
const unsigned char *priv_blob, int priv_len);
|
||||
void *(*openssh_createkey) (const struct ssh_signkey *self,
|
||||
const unsigned char **blob, int *len);
|
||||
int (*openssh_fmtkey) (void *key, unsigned char *blob, int len);
|
||||
/* OpenSSH private key blobs, as created by openssh_fmtkey and
|
||||
* consumed by openssh_createkey, always (at least so far...) take
|
||||
* the form of a number of SSH-2 strings / mpints concatenated
|
||||
* end-to-end. Because the new-style OpenSSH private key format
|
||||
* stores those blobs without a containing string wrapper, we need
|
||||
* to know how many strings each one consists of, so that we can
|
||||
* skip over the right number to find the next key in the file.
|
||||
* openssh_private_npieces gives that information. */
|
||||
int openssh_private_npieces;
|
||||
int (*pubkey_bits) (const struct ssh_signkey *self,
|
||||
const void *blob, int len);
|
||||
int (*verifysig) (void *key, const char *sig, int siglen,
|
||||
const char *data, int datalen);
|
||||
unsigned char *(*sign) (void *key, const char *data, int datalen,
|
||||
int *siglen);
|
||||
const char *name;
|
||||
const char *keytype; /* for host key cache */
|
||||
const void *extra; /* private to the public key methods */
|
||||
struct ssh_keyalg {
|
||||
/* Constructors that create an ssh_key */
|
||||
ssh_key *(*new_pub) (const ssh_keyalg *self, ptrlen pub);
|
||||
ssh_key *(*new_priv) (const ssh_keyalg *self, ptrlen pub, ptrlen priv);
|
||||
ssh_key *(*new_priv_openssh) (const ssh_keyalg *self, BinarySource *);
|
||||
|
||||
/* Methods that operate on an existing ssh_key */
|
||||
void (*freekey) (ssh_key *key);
|
||||
void (*sign) (ssh_key *key, const void *data, int datalen, BinarySink *);
|
||||
int (*verify) (ssh_key *key, ptrlen sig, ptrlen data);
|
||||
void (*public_blob)(ssh_key *key, BinarySink *);
|
||||
void (*private_blob)(ssh_key *key, BinarySink *);
|
||||
void (*openssh_blob) (ssh_key *key, BinarySink *);
|
||||
char *(*cache_str) (ssh_key *key);
|
||||
|
||||
/* 'Class methods' that don't deal with an ssh_key at all */
|
||||
int (*pubkey_bits) (const ssh_keyalg *self, ptrlen blob);
|
||||
|
||||
/* Constant data fields giving information about the key type */
|
||||
const char *ssh_id; /* string identifier in the SSH protocol */
|
||||
const char *cache_id; /* identifier used in PuTTY's host key cache */
|
||||
const void *extra; /* private to the public key methods */
|
||||
};
|
||||
|
||||
#define ssh_key_new_pub(alg, data) ((alg)->new_pub(alg, data))
|
||||
#define ssh_key_new_priv(alg, pub, priv) ((alg)->new_priv(alg, pub, priv))
|
||||
#define ssh_key_new_priv_openssh(alg, bs) ((alg)->new_priv_openssh(alg, bs))
|
||||
|
||||
#define ssh_key_free(key) ((*(key))->freekey(key))
|
||||
#define ssh_key_sign(key, data, len, bs) ((*(key))->sign(key, data, len, bs))
|
||||
#define ssh_key_verify(key, sig, data) ((*(key))->verify(key, sig, data))
|
||||
#define ssh_key_public_blob(key, bs) ((*(key))->public_blob(key, bs))
|
||||
#define ssh_key_private_blob(key, bs) ((*(key))->private_blob(key, bs))
|
||||
#define ssh_key_openssh_blob(key, bs) ((*(key))->openssh_blob(key, bs))
|
||||
#define ssh_key_cache_str(key) ((*(key))->cache_str(key))
|
||||
|
||||
#define ssh_key_public_bits(alg, blob) ((alg)->pubkey_bits(alg, blob))
|
||||
|
||||
#define ssh_key_alg(key) (*(key))
|
||||
#define ssh_key_ssh_id(key) ((*(key))->ssh_id)
|
||||
#define ssh_key_cache_id(key) ((*(key))->cache_id)
|
||||
|
||||
struct ssh_compress {
|
||||
const char *name;
|
||||
/* For zlib@openssh.com: if non-NULL, this name will be considered once
|
||||
@@ -445,19 +579,18 @@ struct ssh_compress {
|
||||
const char *delayed_name;
|
||||
void *(*compress_init) (void);
|
||||
void (*compress_cleanup) (void *);
|
||||
int (*compress) (void *, unsigned char *block, int len,
|
||||
unsigned char **outblock, int *outlen);
|
||||
void (*compress) (void *, unsigned char *block, int len,
|
||||
unsigned char **outblock, int *outlen,
|
||||
int minlen);
|
||||
void *(*decompress_init) (void);
|
||||
void (*decompress_cleanup) (void *);
|
||||
int (*decompress) (void *, unsigned char *block, int len,
|
||||
unsigned char **outblock, int *outlen);
|
||||
int (*disable_compression) (void *);
|
||||
const char *text_name;
|
||||
};
|
||||
|
||||
struct ssh2_userkey {
|
||||
const struct ssh_signkey *alg; /* the key algorithm */
|
||||
void *data; /* the key data */
|
||||
ssh_key *key; /* the key itself */
|
||||
char *comment; /* the key comment */
|
||||
};
|
||||
|
||||
@@ -480,14 +613,15 @@ extern const struct ssh_hash ssh_sha512;
|
||||
extern const struct ssh_kexes ssh_diffiehellman_group1;
|
||||
extern const struct ssh_kexes ssh_diffiehellman_group14;
|
||||
extern const struct ssh_kexes ssh_diffiehellman_gex;
|
||||
extern const struct ssh_kexes ssh_gssk5_sha1_kex;
|
||||
extern const struct ssh_kexes ssh_rsa_kex;
|
||||
extern const struct ssh_kexes ssh_ecdh_kex;
|
||||
extern const struct ssh_signkey ssh_dss;
|
||||
extern const struct ssh_signkey ssh_rsa;
|
||||
extern const struct ssh_signkey ssh_ecdsa_ed25519;
|
||||
extern const struct ssh_signkey ssh_ecdsa_nistp256;
|
||||
extern const struct ssh_signkey ssh_ecdsa_nistp384;
|
||||
extern const struct ssh_signkey ssh_ecdsa_nistp521;
|
||||
extern const ssh_keyalg ssh_dss;
|
||||
extern const ssh_keyalg ssh_rsa;
|
||||
extern const ssh_keyalg ssh_ecdsa_ed25519;
|
||||
extern const ssh_keyalg ssh_ecdsa_nistp256;
|
||||
extern const ssh_keyalg ssh_ecdsa_nistp384;
|
||||
extern const ssh_keyalg ssh_ecdsa_nistp521;
|
||||
extern const struct ssh_mac ssh_hmac_md5;
|
||||
extern const struct ssh_mac ssh_hmac_sha1;
|
||||
extern const struct ssh_mac ssh_hmac_sha1_buggy;
|
||||
@@ -497,13 +631,13 @@ extern const struct ssh_mac ssh_hmac_sha256;
|
||||
|
||||
void *aes_make_context(void);
|
||||
void aes_free_context(void *handle);
|
||||
void aes128_key(void *handle, unsigned char *key);
|
||||
void aes192_key(void *handle, unsigned char *key);
|
||||
void aes256_key(void *handle, unsigned char *key);
|
||||
void aes_iv(void *handle, unsigned char *iv);
|
||||
void aes_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len);
|
||||
void aes_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len);
|
||||
void aes_ssh2_sdctr(void *handle, unsigned char *blk, int len);
|
||||
void aes128_key(void *handle, const void *key);
|
||||
void aes192_key(void *handle, const void *key);
|
||||
void aes256_key(void *handle, const void *key);
|
||||
void aes_iv(void *handle, const void *iv);
|
||||
void aes_ssh2_encrypt_blk(void *handle, void *blk, int len);
|
||||
void aes_ssh2_decrypt_blk(void *handle, void *blk, int len);
|
||||
void aes_ssh2_sdctr(void *handle, void *blk, int len);
|
||||
|
||||
/*
|
||||
* PuTTY version number formatted as an SSH version string.
|
||||
@@ -521,8 +655,29 @@ extern
|
||||
*/
|
||||
extern int ssh_fallback_cmd(void *handle);
|
||||
|
||||
#ifndef MSCRYPTOAPI
|
||||
void SHATransform(word32 * digest, word32 * data);
|
||||
|
||||
/*
|
||||
* Check of compiler version
|
||||
*/
|
||||
#ifdef _FORCE_SHA_NI
|
||||
# define COMPILER_SUPPORTS_SHA_NI
|
||||
#elif defined(__clang__)
|
||||
# if __has_attribute(target) && __has_include(<shaintrin.h>) && (defined(__x86_64__) || defined(__i386))
|
||||
# define COMPILER_SUPPORTS_SHA_NI
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if ((__GNUC__ >= 5) && (defined(__x86_64__) || defined(__i386)))
|
||||
# define COMPILER_SUPPORTS_SHA_NI
|
||||
# endif
|
||||
#elif defined (_MSC_VER)
|
||||
# if (defined(_M_X64) || defined(_M_IX86)) && _MSC_VER >= 1900
|
||||
# define COMPILER_SUPPORTS_SHA_NI
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _FORCE_SOFTWARE_SHA
|
||||
# undef COMPILER_SUPPORTS_SHA_NI
|
||||
#endif
|
||||
|
||||
int random_byte(void);
|
||||
@@ -542,7 +697,7 @@ void ssh_send_port_open(void *channel, const char *hostname, int port,
|
||||
extern char *pfd_connect(struct PortForwarding **pf, char *hostname, int port,
|
||||
void *c, Conf *conf, int addressfamily);
|
||||
extern void pfd_close(struct PortForwarding *);
|
||||
extern int pfd_send(struct PortForwarding *, char *data, int len);
|
||||
extern int pfd_send(struct PortForwarding *, const void *data, int len);
|
||||
extern void pfd_send_eof(struct PortForwarding *);
|
||||
extern void pfd_confirm(struct PortForwarding *);
|
||||
extern void pfd_unthrottle(struct PortForwarding *);
|
||||
@@ -622,7 +777,7 @@ void x11_free_fake_auth(struct X11FakeAuth *auth);
|
||||
struct X11Connection; /* opaque outside x11fwd.c */
|
||||
struct X11Connection *x11_init(tree234 *authtree, void *, const char *, int);
|
||||
extern void x11_close(struct X11Connection *);
|
||||
extern int x11_send(struct X11Connection *, char *, int);
|
||||
extern int x11_send(struct X11Connection *, const void *, int);
|
||||
extern void x11_send_eof(struct X11Connection *s);
|
||||
extern void x11_unthrottle(struct X11Connection *s);
|
||||
extern void x11_override_throttle(struct X11Connection *s, int enable);
|
||||
@@ -652,8 +807,8 @@ char *platform_get_x_display(void);
|
||||
*/
|
||||
void x11_get_auth_from_authfile(struct X11Display *display,
|
||||
const char *authfilename);
|
||||
int x11_identify_auth_proto(const char *proto);
|
||||
void *x11_dehexify(const char *hex, int *outlen);
|
||||
int x11_identify_auth_proto(ptrlen protoname);
|
||||
void *x11_dehexify(ptrlen hex, int *outlen);
|
||||
|
||||
Bignum copybn(Bignum b);
|
||||
Bignum bn_power_2(int n);
|
||||
@@ -665,17 +820,13 @@ Bignum modmul(Bignum a, Bignum b, Bignum mod);
|
||||
Bignum modsub(const Bignum a, const Bignum b, const Bignum n);
|
||||
void decbn(Bignum n);
|
||||
extern Bignum Zero, One;
|
||||
Bignum bignum_from_bytes(const unsigned char *data, int nbytes);
|
||||
Bignum bignum_from_bytes_le(const unsigned char *data, int nbytes);
|
||||
Bignum bignum_from_bytes(const void *data, int nbytes);
|
||||
Bignum bignum_from_bytes_le(const void *data, int nbytes);
|
||||
Bignum bignum_random_in_range(const Bignum lower, const Bignum upper);
|
||||
int ssh1_read_bignum(const unsigned char *data, int len, Bignum * result);
|
||||
int bignum_bitcount(Bignum bn);
|
||||
int ssh1_bignum_length(Bignum bn);
|
||||
int ssh2_bignum_length(Bignum bn);
|
||||
int bignum_byte(Bignum bn, int i);
|
||||
int bignum_bit(Bignum bn, int i);
|
||||
void bignum_set_bit(Bignum bn, int i, int value);
|
||||
int ssh1_write_bignum(void *data, Bignum bn);
|
||||
Bignum biggcd(Bignum a, Bignum b);
|
||||
unsigned short bignum_mod_short(Bignum number, unsigned short modulus);
|
||||
Bignum bignum_add_long(Bignum number, unsigned long addend);
|
||||
@@ -693,6 +844,11 @@ int bignum_cmp(Bignum a, Bignum b);
|
||||
char *bignum_decimal(Bignum x);
|
||||
Bignum bignum_from_decimal(const char *decimal);
|
||||
|
||||
void BinarySink_put_mp_ssh1(BinarySink *, Bignum);
|
||||
void BinarySink_put_mp_ssh2(BinarySink *, Bignum);
|
||||
Bignum BinarySource_get_mp_ssh1(BinarySource *);
|
||||
Bignum BinarySource_get_mp_ssh2(BinarySource *);
|
||||
|
||||
#ifdef DEBUG
|
||||
void diagbn(char *prefix, Bignum md);
|
||||
#endif
|
||||
@@ -705,13 +861,13 @@ Bignum dh_create_e(void *, int nbits);
|
||||
const char *dh_validate_f(void *handle, Bignum f);
|
||||
Bignum dh_find_K(void *, Bignum f);
|
||||
|
||||
int loadrsakey(const Filename *filename, struct RSAKey *key,
|
||||
const char *passphrase, const char **errorstr);
|
||||
int rsakey_encrypted(const Filename *filename, char **comment);
|
||||
int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
|
||||
char **commentptr, const char **errorstr);
|
||||
|
||||
int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase);
|
||||
int rsa_ssh1_encrypted(const Filename *filename, char **comment);
|
||||
int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
|
||||
char **commentptr, const char **errorstr);
|
||||
int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key,
|
||||
const char *passphrase, const char **errorstr);
|
||||
int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key,
|
||||
char *passphrase);
|
||||
|
||||
extern int base64_decode_atom(const char *atom, unsigned char *out);
|
||||
extern int base64_lines(int datalen);
|
||||
@@ -727,13 +883,13 @@ int ssh2_userkey_encrypted(const Filename *filename, char **comment);
|
||||
struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
|
||||
const char *passphrase,
|
||||
const char **errorstr);
|
||||
unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
|
||||
int *pub_blob_len, char **commentptr,
|
||||
const char **errorstr);
|
||||
int ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
|
||||
BinarySink *bs,
|
||||
char **commentptr, const char **errorstr);
|
||||
int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
|
||||
char *passphrase);
|
||||
const struct ssh_signkey *find_pubkey_alg(const char *name);
|
||||
const struct ssh_signkey *find_pubkey_alg_len(int namelen, const char *name);
|
||||
const ssh_keyalg *find_pubkey_alg(const char *name);
|
||||
const ssh_keyalg *find_pubkey_alg_len(ptrlen name);
|
||||
|
||||
enum {
|
||||
SSH_KEYTYPE_UNOPENABLE,
|
||||
@@ -785,13 +941,13 @@ void ssh2_write_pubkey(FILE *fp, const char *comment,
|
||||
const void *v_pub_blob, int pub_len,
|
||||
int keytype);
|
||||
char *ssh2_fingerprint_blob(const void *blob, int bloblen);
|
||||
char *ssh2_fingerprint(const struct ssh_signkey *alg, void *data);
|
||||
char *ssh2_fingerprint(ssh_key *key);
|
||||
int key_type(const Filename *filename);
|
||||
const char *key_type_to_str(int type);
|
||||
#ifdef MPEXT
|
||||
unsigned char *openssh_loadpub_line(char * line, char **algorithm,
|
||||
int *pub_blob_len, char **commentptr,
|
||||
const char **errorstr);
|
||||
int openssh_loadpub_line(char * line, char **algorithm,
|
||||
BinarySink *bs,
|
||||
char **commentptr, const char **errorstr);
|
||||
#endif
|
||||
|
||||
int import_possible(int type);
|
||||
@@ -806,21 +962,17 @@ int export_ssh1(const Filename *filename, int type,
|
||||
int export_ssh2(const Filename *filename, int type,
|
||||
struct ssh2_userkey *key, char *passphrase);
|
||||
|
||||
void des3_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len);
|
||||
void des3_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len);
|
||||
void des3_decrypt_pubkey_ossh(unsigned char *key, unsigned char *iv,
|
||||
unsigned char *blk, int len);
|
||||
void des3_encrypt_pubkey_ossh(unsigned char *key, unsigned char *iv,
|
||||
unsigned char *blk, int len);
|
||||
void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk,
|
||||
int len);
|
||||
void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk,
|
||||
int len);
|
||||
void des3_decrypt_pubkey(const void *key, void *blk, int len);
|
||||
void des3_encrypt_pubkey(const void *key, void *blk, int len);
|
||||
void des3_decrypt_pubkey_ossh(const void *key, const void *iv,
|
||||
void *blk, int len);
|
||||
void des3_encrypt_pubkey_ossh(const void *key, const void *iv,
|
||||
void *blk, int len);
|
||||
void aes256_encrypt_pubkey(const void *key, void *blk, int len);
|
||||
void aes256_decrypt_pubkey(const void *key, void *blk, int len);
|
||||
|
||||
void des_encrypt_xdmauth(const unsigned char *key,
|
||||
unsigned char *blk, int len);
|
||||
void des_decrypt_xdmauth(const unsigned char *key,
|
||||
unsigned char *blk, int len);
|
||||
void des_encrypt_xdmauth(const void *key, void *blk, int len);
|
||||
void des_decrypt_xdmauth(const void *key, void *blk, int len);
|
||||
|
||||
void openssh_bcrypt(const char *passphrase,
|
||||
const unsigned char *salt, int saltbytes,
|
||||
@@ -857,8 +1009,8 @@ void *zlib_compress_init(void);
|
||||
void zlib_compress_cleanup(void *);
|
||||
void *zlib_decompress_init(void);
|
||||
void zlib_decompress_cleanup(void *);
|
||||
int zlib_compress_block(void *, unsigned char *block, int len,
|
||||
unsigned char **outblock, int *outlen);
|
||||
void zlib_compress_block(void *, unsigned char *block, int len,
|
||||
unsigned char **outblock, int *outlen, int minlen);
|
||||
int zlib_decompress_block(void *, unsigned char *block, int len,
|
||||
unsigned char **outblock, int *outlen);
|
||||
|
||||
@@ -952,6 +1104,13 @@ void platform_ssh_share_cleanup(const char *name);
|
||||
#define SSH2_MSG_KEX_DH_GEX_GROUP 31 /* 0x1f */
|
||||
#define SSH2_MSG_KEX_DH_GEX_INIT 32 /* 0x20 */
|
||||
#define SSH2_MSG_KEX_DH_GEX_REPLY 33 /* 0x21 */
|
||||
#define SSH2_MSG_KEXGSS_INIT 30 /* 0x1e */
|
||||
#define SSH2_MSG_KEXGSS_CONTINUE 31 /* 0x1f */
|
||||
#define SSH2_MSG_KEXGSS_COMPLETE 32 /* 0x20 */
|
||||
#define SSH2_MSG_KEXGSS_HOSTKEY 33 /* 0x21 */
|
||||
#define SSH2_MSG_KEXGSS_ERROR 34 /* 0x22 */
|
||||
#define SSH2_MSG_KEXGSS_GROUPREQ 40 /* 0x28 */
|
||||
#define SSH2_MSG_KEXGSS_GROUP 41 /* 0x29 */
|
||||
#define SSH2_MSG_KEXRSA_PUBKEY 30 /* 0x1e */
|
||||
#define SSH2_MSG_KEXRSA_SECRET 31 /* 0x1f */
|
||||
#define SSH2_MSG_KEXRSA_DONE 32 /* 0x20 */
|
||||
@@ -988,6 +1147,13 @@ void platform_ssh_share_cleanup(const char *name);
|
||||
#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65
|
||||
#define SSH2_MSG_USERAUTH_GSSAPI_MIC 66
|
||||
|
||||
/* Virtual packet type, for packets too short to even have a type */
|
||||
#define SSH_MSG_NO_TYPE_CODE 0x100
|
||||
|
||||
/* Given that virtual packet types exist, this is how big the dispatch
|
||||
* table has to be */
|
||||
#define SSH_MAX_MSG 0x101
|
||||
|
||||
/*
|
||||
* SSH-1 agent messages.
|
||||
*/
|
||||
@@ -1042,6 +1208,9 @@ void platform_ssh_share_cleanup(const char *name);
|
||||
|
||||
#define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 */
|
||||
|
||||
const char *ssh1_pkt_type(int type);
|
||||
const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type);
|
||||
|
||||
/*
|
||||
* Need this to warn about support for the original SSH-2 keyfile
|
||||
* format.
|
||||
|
||||
294
source/putty/ssh1bpp.c
vendored
Normal file
294
source/putty/ssh1bpp.c
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Binary packet protocol for SSH-1.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshbpp.h"
|
||||
#include "sshcr.h"
|
||||
|
||||
struct ssh1_bpp_state {
|
||||
int crState;
|
||||
long len, pad, biglen, length, maxlen;
|
||||
unsigned char *data;
|
||||
unsigned long realcrc, gotcrc;
|
||||
int chunk;
|
||||
PktIn *pktin;
|
||||
|
||||
const struct ssh_cipher *cipher;
|
||||
void *cipher_ctx;
|
||||
|
||||
void *crcda_ctx;
|
||||
|
||||
void *compctx, *decompctx;
|
||||
|
||||
BinaryPacketProtocol bpp;
|
||||
};
|
||||
|
||||
static void ssh1_bpp_free(BinaryPacketProtocol *bpp);
|
||||
static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp);
|
||||
static PktOut *ssh1_bpp_new_pktout(int type);
|
||||
static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt);
|
||||
|
||||
const struct BinaryPacketProtocolVtable ssh1_bpp_vtable = {
|
||||
ssh1_bpp_free,
|
||||
ssh1_bpp_handle_input,
|
||||
ssh1_bpp_new_pktout,
|
||||
ssh1_bpp_format_packet,
|
||||
};
|
||||
|
||||
BinaryPacketProtocol *ssh1_bpp_new(void)
|
||||
{
|
||||
struct ssh1_bpp_state *s = snew(struct ssh1_bpp_state);
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->bpp.vt = &ssh1_bpp_vtable;
|
||||
return &s->bpp;
|
||||
}
|
||||
|
||||
static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp);
|
||||
if (s->cipher)
|
||||
s->cipher->free_context(s->cipher_ctx);
|
||||
if (s->compctx)
|
||||
zlib_compress_cleanup(s->compctx);
|
||||
if (s->decompctx)
|
||||
zlib_decompress_cleanup(s->decompctx);
|
||||
if (s->crcda_ctx)
|
||||
crcda_free_context(s->crcda_ctx);
|
||||
if (s->pktin)
|
||||
ssh_unref_packet(s->pktin);
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
|
||||
const struct ssh_cipher *cipher,
|
||||
const void *session_key)
|
||||
{
|
||||
struct ssh1_bpp_state *s;
|
||||
assert(bpp->vt == &ssh1_bpp_vtable);
|
||||
s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp);
|
||||
|
||||
assert(!s->cipher);
|
||||
|
||||
s->cipher = cipher;
|
||||
if (s->cipher) {
|
||||
s->cipher_ctx = cipher->make_context();
|
||||
cipher->sesskey(s->cipher_ctx, session_key);
|
||||
|
||||
assert(!s->crcda_ctx);
|
||||
s->crcda_ctx = crcda_make_context();
|
||||
}
|
||||
}
|
||||
|
||||
void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh1_bpp_state *s;
|
||||
assert(bpp->vt == &ssh1_bpp_vtable);
|
||||
s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp);
|
||||
|
||||
assert(!s->compctx);
|
||||
assert(!s->decompctx);
|
||||
|
||||
s->compctx = zlib_compress_init();
|
||||
s->decompctx = zlib_decompress_init();
|
||||
}
|
||||
|
||||
static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp);
|
||||
|
||||
crBegin(s->crState);
|
||||
|
||||
while (1) {
|
||||
s->maxlen = 0;
|
||||
s->length = 0;
|
||||
|
||||
{
|
||||
unsigned char lenbuf[4];
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
bpp->in_raw, lenbuf, 4));
|
||||
s->len = toint(GET_32BIT_MSB_FIRST(lenbuf));
|
||||
}
|
||||
|
||||
if (s->len < 0 || s->len > 262144) { /* SSH1.5-mandated max size */
|
||||
s->bpp.error = dupprintf(
|
||||
"Extremely large packet length from server suggests"
|
||||
" data stream corruption");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
s->pad = 8 - (s->len % 8);
|
||||
s->biglen = s->len + s->pad;
|
||||
s->length = s->len - 5;
|
||||
|
||||
/*
|
||||
* Allocate the packet to return, now we know its length.
|
||||
*/
|
||||
s->pktin = snew_plus(PktIn, s->biglen);
|
||||
s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
|
||||
s->pktin->refcount = 1;
|
||||
s->pktin->type = 0;
|
||||
|
||||
s->maxlen = s->biglen;
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
bpp->in_raw, s->data, s->biglen));
|
||||
|
||||
if (s->cipher && detect_attack(s->crcda_ctx,
|
||||
s->data, s->biglen, NULL)) {
|
||||
s->bpp.error = dupprintf(
|
||||
"Network attack (CRC compensation) detected!");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
if (s->cipher)
|
||||
s->cipher->decrypt(s->cipher_ctx, s->data, s->biglen);
|
||||
|
||||
s->realcrc = crc32_compute(s->data, s->biglen - 4);
|
||||
s->gotcrc = GET_32BIT(s->data + s->biglen - 4);
|
||||
if (s->gotcrc != s->realcrc) {
|
||||
s->bpp.error = dupprintf(
|
||||
"Incorrect CRC received on packet");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
if (s->decompctx) {
|
||||
unsigned char *decompblk;
|
||||
int decomplen;
|
||||
if (!zlib_decompress_block(s->decompctx,
|
||||
s->data + s->pad, s->length + 1,
|
||||
&decompblk, &decomplen)) {
|
||||
s->bpp.error = dupprintf(
|
||||
"Zlib decompression encountered invalid data");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
if (s->maxlen < s->pad + decomplen) {
|
||||
PktIn *old_pktin = s->pktin;
|
||||
|
||||
s->maxlen = s->pad + decomplen;
|
||||
s->pktin = snew_plus(PktIn, s->maxlen);
|
||||
*s->pktin = *old_pktin; /* structure copy */
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
|
||||
smemclr(old_pktin, s->biglen);
|
||||
sfree(old_pktin);
|
||||
}
|
||||
|
||||
memcpy(s->data + s->pad, decompblk, decomplen);
|
||||
sfree(decompblk);
|
||||
s->length = decomplen - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we can find the bounds of the semantic content of the
|
||||
* packet, and the initial type byte.
|
||||
*/
|
||||
s->data += s->pad;
|
||||
s->pktin->type = *s->data++;
|
||||
BinarySource_INIT(s->pktin, s->data, s->length);
|
||||
|
||||
if (s->bpp.logctx) {
|
||||
logblank_t blanks[MAX_BLANKS];
|
||||
int nblanks = ssh1_censor_packet(
|
||||
s->bpp.pls, s->pktin->type, FALSE,
|
||||
make_ptrlen(s->data, s->length), blanks);
|
||||
log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type,
|
||||
ssh1_pkt_type(s->pktin->type),
|
||||
get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
pq_push(s->bpp.in_pq, s->pktin);
|
||||
|
||||
{
|
||||
int type = s->pktin->type;
|
||||
s->pktin = NULL;
|
||||
|
||||
if (type == SSH1_MSG_DISCONNECT)
|
||||
s->bpp.seen_disconnect = TRUE;
|
||||
}
|
||||
}
|
||||
crFinishV;
|
||||
}
|
||||
|
||||
static PktOut *ssh1_bpp_new_pktout(int pkt_type)
|
||||
{
|
||||
PktOut *pkt = ssh_new_packet();
|
||||
pkt->length = 4 + 8; /* space for length + max padding */
|
||||
put_byte(pkt, pkt_type);
|
||||
pkt->prefix = pkt->length;
|
||||
pkt->type = pkt_type;
|
||||
pkt->downstream_id = 0;
|
||||
pkt->additional_log_text = NULL;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
|
||||
{
|
||||
struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp);
|
||||
int pad, biglen, i, pktoffs;
|
||||
unsigned long crc;
|
||||
int len;
|
||||
|
||||
if (s->bpp.logctx) {
|
||||
ptrlen pktdata = make_ptrlen(pkt->data + pkt->prefix,
|
||||
pkt->length - pkt->prefix);
|
||||
logblank_t blanks[MAX_BLANKS];
|
||||
int nblanks = ssh1_censor_packet(
|
||||
s->bpp.pls, pkt->type, TRUE, pktdata, blanks);
|
||||
log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type,
|
||||
ssh1_pkt_type(pkt->type),
|
||||
pktdata.ptr, pktdata.len, nblanks, blanks,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (s->compctx) {
|
||||
unsigned char *compblk;
|
||||
int complen;
|
||||
zlib_compress_block(s->compctx, pkt->data + 12, pkt->length - 12,
|
||||
&compblk, &complen, 0);
|
||||
/* Replace the uncompressed packet data with the compressed
|
||||
* version. */
|
||||
pkt->length = 12;
|
||||
put_data(pkt, compblk, complen);
|
||||
sfree(compblk);
|
||||
}
|
||||
|
||||
put_uint32(pkt, 0); /* space for CRC */
|
||||
len = pkt->length - 4 - 8; /* len(type+data+CRC) */
|
||||
pad = 8 - (len % 8);
|
||||
pktoffs = 8 - pad;
|
||||
biglen = len + pad; /* len(padding+type+data+CRC) */
|
||||
|
||||
for (i = pktoffs; i < 4+8; i++)
|
||||
pkt->data[i] = random_byte();
|
||||
crc = crc32_compute(pkt->data + pktoffs + 4,
|
||||
biglen - 4); /* all ex len */
|
||||
PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc);
|
||||
PUT_32BIT(pkt->data + pktoffs, len);
|
||||
|
||||
if (s->cipher)
|
||||
s->cipher->encrypt(s->cipher_ctx, pkt->data + pktoffs + 4, biglen);
|
||||
|
||||
bufchain_add(s->bpp.out_raw, pkt->data + pktoffs,
|
||||
biglen + 4); /* len(length+padding+type+data+CRC) */
|
||||
|
||||
ssh_free_pktout(pkt);
|
||||
}
|
||||
|
||||
#ifdef MPEXT
|
||||
int ssh1_bpp_get_compressing(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
return FROMFIELD(bpp, struct ssh1_bpp_state, bpp)->compctx != NULL;
|
||||
}
|
||||
|
||||
const struct ssh_cipher * ssh1_bpp_get_cipher(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
return FROMFIELD(bpp, struct ssh1_bpp_state, bpp)->cipher;
|
||||
}
|
||||
#endif
|
||||
76
source/putty/ssh1censor.c
vendored
Normal file
76
source/putty/ssh1censor.c
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Packet-censoring code for SSH-1, used to identify sensitive fields
|
||||
* like passwords so that the logging system can avoid writing them
|
||||
* into log files.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
int ssh1_censor_packet(
|
||||
const PacketLogSettings *pls, int type, int sender_is_client,
|
||||
ptrlen pkt, logblank_t *blanks)
|
||||
{
|
||||
int nblanks = 0;
|
||||
ptrlen str;
|
||||
BinarySource src[1];
|
||||
|
||||
BinarySource_BARE_INIT(src, pkt.ptr, pkt.len);
|
||||
|
||||
if (pls->omit_data &&
|
||||
(type == SSH1_SMSG_STDOUT_DATA ||
|
||||
type == SSH1_SMSG_STDERR_DATA ||
|
||||
type == SSH1_CMSG_STDIN_DATA ||
|
||||
type == SSH1_MSG_CHANNEL_DATA)) {
|
||||
/* "Session data" packets - omit the data string. */
|
||||
if (type == SSH1_MSG_CHANNEL_DATA)
|
||||
get_uint32(src); /* skip channel id */
|
||||
str = get_string(src);
|
||||
if (!get_err(src)) {
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = src->pos - str.len;
|
||||
blanks[nblanks].type = PKTLOG_OMIT;
|
||||
blanks[nblanks].len = str.len;
|
||||
nblanks++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sender_is_client && pls->omit_passwords) {
|
||||
if (type == SSH1_CMSG_AUTH_PASSWORD ||
|
||||
type == SSH1_CMSG_AUTH_TIS_RESPONSE ||
|
||||
type == SSH1_CMSG_AUTH_CCARD_RESPONSE) {
|
||||
/* If this is a password or similar packet, blank the
|
||||
* password(s). */
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = 0;
|
||||
blanks[nblanks].len = pkt.len;
|
||||
blanks[nblanks].type = PKTLOG_BLANK;
|
||||
nblanks++;
|
||||
} else if (type == SSH1_CMSG_X11_REQUEST_FORWARDING) {
|
||||
/*
|
||||
* If this is an X forwarding request packet, blank the
|
||||
* fake auth data.
|
||||
*
|
||||
* Note that while we blank the X authentication data
|
||||
* here, we don't take any special action to blank the
|
||||
* start of an X11 channel, so using MIT-MAGIC-COOKIE-1
|
||||
* and actually opening an X connection without having
|
||||
* session blanking enabled is likely to leak your cookie
|
||||
* into the log.
|
||||
*/
|
||||
get_string(src); /* skip protocol name */
|
||||
str = get_string(src);
|
||||
if (!get_err(src)) {
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = src->pos - str.len;
|
||||
blanks[nblanks].type = PKTLOG_BLANK;
|
||||
blanks[nblanks].len = str.len;
|
||||
nblanks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nblanks;
|
||||
}
|
||||
162
source/putty/ssh2bpp-bare.c
vendored
Normal file
162
source/putty/ssh2bpp-bare.c
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Trivial binary packet protocol for the 'bare' ssh-connection
|
||||
* protocol used in PuTTY's SSH-2 connection sharing system.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshbpp.h"
|
||||
#include "sshcr.h"
|
||||
|
||||
struct ssh2_bare_bpp_state {
|
||||
int crState;
|
||||
long packetlen, maxlen;
|
||||
unsigned char *data;
|
||||
unsigned long incoming_sequence, outgoing_sequence;
|
||||
PktIn *pktin;
|
||||
|
||||
BinaryPacketProtocol bpp;
|
||||
};
|
||||
|
||||
static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp);
|
||||
static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp);
|
||||
static PktOut *ssh2_bare_bpp_new_pktout(int type);
|
||||
static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *);
|
||||
|
||||
const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = {
|
||||
ssh2_bare_bpp_free,
|
||||
ssh2_bare_bpp_handle_input,
|
||||
ssh2_bare_bpp_new_pktout,
|
||||
ssh2_bare_bpp_format_packet,
|
||||
};
|
||||
|
||||
BinaryPacketProtocol *ssh2_bare_bpp_new(void)
|
||||
{
|
||||
struct ssh2_bare_bpp_state *s = snew(struct ssh2_bare_bpp_state);
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->bpp.vt = &ssh2_bare_bpp_vtable;
|
||||
return &s->bpp;
|
||||
}
|
||||
|
||||
static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh2_bare_bpp_state *s =
|
||||
FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp);
|
||||
if (s->pktin)
|
||||
ssh_unref_packet(s->pktin);
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh2_bare_bpp_state *s =
|
||||
FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp);
|
||||
|
||||
crBegin(s->crState);
|
||||
|
||||
while (1) {
|
||||
/* Read the length field. */
|
||||
{
|
||||
unsigned char lenbuf[4];
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
s->bpp.in_raw, lenbuf, 4));
|
||||
s->packetlen = toint(GET_32BIT_MSB_FIRST(lenbuf));
|
||||
}
|
||||
|
||||
if (s->packetlen <= 0 || s->packetlen >= (long)OUR_V2_PACKETLIMIT) {
|
||||
s->bpp.error = dupstr("Invalid packet length received");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the packet to return, now we know its length.
|
||||
*/
|
||||
s->pktin = snew_plus(PktIn, s->packetlen);
|
||||
s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
|
||||
s->maxlen = 0;
|
||||
s->pktin->refcount = 1;
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
|
||||
s->pktin->encrypted_len = s->packetlen;
|
||||
|
||||
s->pktin->sequence = s->incoming_sequence++;
|
||||
|
||||
/*
|
||||
* Read the remainder of the packet.
|
||||
*/
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
s->bpp.in_raw, s->data, s->packetlen));
|
||||
|
||||
/*
|
||||
* The data we just read is precisely the initial type byte
|
||||
* followed by the packet payload.
|
||||
*/
|
||||
s->pktin->type = s->data[0];
|
||||
s->data++;
|
||||
s->packetlen--;
|
||||
BinarySource_INIT(s->pktin, s->data, s->packetlen);
|
||||
|
||||
/*
|
||||
* Log incoming packet, possibly omitting sensitive fields.
|
||||
*/
|
||||
if (s->bpp.logctx) {
|
||||
logblank_t blanks[MAX_BLANKS];
|
||||
int nblanks = ssh2_censor_packet(
|
||||
s->bpp.pls, s->pktin->type, FALSE,
|
||||
make_ptrlen(s->data, s->packetlen), blanks);
|
||||
log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type,
|
||||
ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
|
||||
s->pktin->type),
|
||||
get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks,
|
||||
&s->pktin->sequence, 0, NULL);
|
||||
}
|
||||
|
||||
pq_push(s->bpp.in_pq, s->pktin);
|
||||
|
||||
{
|
||||
int type = s->pktin->type;
|
||||
s->pktin = NULL;
|
||||
|
||||
if (type == SSH2_MSG_DISCONNECT)
|
||||
s->bpp.seen_disconnect = TRUE;
|
||||
}
|
||||
}
|
||||
crFinishV;
|
||||
}
|
||||
|
||||
static PktOut *ssh2_bare_bpp_new_pktout(int pkt_type)
|
||||
{
|
||||
PktOut *pkt = ssh_new_packet();
|
||||
pkt->length = 4; /* space for packet length */
|
||||
pkt->type = pkt_type;
|
||||
put_byte(pkt, pkt_type);
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
|
||||
{
|
||||
struct ssh2_bare_bpp_state *s =
|
||||
FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp);
|
||||
|
||||
if (s->bpp.logctx) {
|
||||
ptrlen pktdata = make_ptrlen(pkt->data + 5, pkt->length - 5);
|
||||
logblank_t blanks[MAX_BLANKS];
|
||||
int nblanks = ssh2_censor_packet(
|
||||
s->bpp.pls, pkt->type, TRUE, pktdata, blanks);
|
||||
log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type,
|
||||
ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
|
||||
pkt->type),
|
||||
pktdata.ptr, pktdata.len, nblanks, blanks,
|
||||
&s->outgoing_sequence,
|
||||
pkt->downstream_id, pkt->additional_log_text);
|
||||
}
|
||||
|
||||
s->outgoing_sequence++; /* only for diagnostics, really */
|
||||
|
||||
PUT_32BIT(pkt->data, pkt->length - 4);
|
||||
bufchain_add(s->bpp.out_raw, pkt->data, pkt->length);
|
||||
|
||||
ssh_free_pktout(pkt);
|
||||
}
|
||||
702
source/putty/ssh2bpp.c
vendored
Normal file
702
source/putty/ssh2bpp.c
vendored
Normal file
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
* Binary packet protocol for SSH-2.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshbpp.h"
|
||||
#include "sshcr.h"
|
||||
|
||||
struct ssh2_bpp_direction {
|
||||
unsigned long sequence;
|
||||
const struct ssh2_cipher *cipher;
|
||||
void *cipher_ctx;
|
||||
const struct ssh_mac *mac;
|
||||
int etm_mode;
|
||||
void *mac_ctx;
|
||||
const struct ssh_compress *comp;
|
||||
void *comp_ctx;
|
||||
};
|
||||
|
||||
struct ssh2_bpp_state {
|
||||
int crState;
|
||||
long len, pad, payload, packetlen, maclen, length, maxlen;
|
||||
unsigned char *buf;
|
||||
size_t bufsize;
|
||||
unsigned char *data;
|
||||
unsigned cipherblk;
|
||||
PktIn *pktin;
|
||||
BinarySink *sc_mac_bs;
|
||||
|
||||
struct ssh2_bpp_direction in, out;
|
||||
int pending_newkeys;
|
||||
|
||||
BinaryPacketProtocol bpp;
|
||||
};
|
||||
|
||||
static void ssh2_bpp_free(BinaryPacketProtocol *bpp);
|
||||
static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp);
|
||||
static PktOut *ssh2_bpp_new_pktout(int type);
|
||||
static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt);
|
||||
|
||||
const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = {
|
||||
ssh2_bpp_free,
|
||||
ssh2_bpp_handle_input,
|
||||
ssh2_bpp_new_pktout,
|
||||
ssh2_bpp_format_packet,
|
||||
};
|
||||
|
||||
BinaryPacketProtocol *ssh2_bpp_new(void)
|
||||
{
|
||||
struct ssh2_bpp_state *s = snew(struct ssh2_bpp_state);
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->bpp.vt = &ssh2_bpp_vtable;
|
||||
return &s->bpp;
|
||||
}
|
||||
|
||||
static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
|
||||
sfree(s->buf);
|
||||
if (s->out.cipher_ctx)
|
||||
s->out.cipher->free_context(s->out.cipher_ctx);
|
||||
if (s->out.mac_ctx)
|
||||
s->out.mac->free_context(s->out.mac_ctx);
|
||||
if (s->out.comp_ctx)
|
||||
s->out.comp->compress_cleanup(s->out.comp_ctx);
|
||||
if (s->in.cipher_ctx)
|
||||
s->in.cipher->free_context(s->in.cipher_ctx);
|
||||
if (s->in.mac_ctx)
|
||||
s->in.mac->free_context(s->in.mac_ctx);
|
||||
if (s->in.comp_ctx)
|
||||
s->in.comp->decompress_cleanup(s->in.comp_ctx);
|
||||
if (s->pktin)
|
||||
ssh_unref_packet(s->pktin);
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
void ssh2_bpp_new_outgoing_crypto(
|
||||
BinaryPacketProtocol *bpp,
|
||||
const struct ssh2_cipher *cipher, const void *ckey, const void *iv,
|
||||
const struct ssh_mac *mac, int etm_mode, const void *mac_key,
|
||||
const struct ssh_compress *compression)
|
||||
{
|
||||
struct ssh2_bpp_state *s;
|
||||
assert(bpp->vt == &ssh2_bpp_vtable);
|
||||
s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
|
||||
|
||||
if (s->out.cipher_ctx)
|
||||
s->out.cipher->free_context(s->out.cipher_ctx);
|
||||
if (s->out.mac_ctx)
|
||||
s->out.mac->free_context(s->out.mac_ctx);
|
||||
if (s->out.comp_ctx)
|
||||
s->out.comp->compress_cleanup(s->out.comp_ctx);
|
||||
|
||||
s->out.cipher = cipher;
|
||||
if (cipher) {
|
||||
s->out.cipher_ctx = cipher->make_context();
|
||||
cipher->setkey(s->out.cipher_ctx, ckey);
|
||||
cipher->setiv(s->out.cipher_ctx, iv);
|
||||
}
|
||||
s->out.mac = mac;
|
||||
s->out.etm_mode = etm_mode;
|
||||
if (mac) {
|
||||
s->out.mac_ctx = mac->make_context(s->out.cipher_ctx);
|
||||
mac->setkey(s->out.mac_ctx, mac_key);
|
||||
}
|
||||
|
||||
s->out.comp = compression;
|
||||
/* out_comp is always non-NULL, because no compression is
|
||||
* indicated by ssh_comp_none. So compress_init always exists, but
|
||||
* it may return a null out_comp_ctx. */
|
||||
s->out.comp_ctx = compression->compress_init();
|
||||
}
|
||||
|
||||
void ssh2_bpp_new_incoming_crypto(
|
||||
BinaryPacketProtocol *bpp,
|
||||
const struct ssh2_cipher *cipher, const void *ckey, const void *iv,
|
||||
const struct ssh_mac *mac, int etm_mode, const void *mac_key,
|
||||
const struct ssh_compress *compression)
|
||||
{
|
||||
struct ssh2_bpp_state *s;
|
||||
assert(bpp->vt == &ssh2_bpp_vtable);
|
||||
s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
|
||||
|
||||
if (s->in.cipher_ctx)
|
||||
s->in.cipher->free_context(s->in.cipher_ctx);
|
||||
if (s->in.mac_ctx)
|
||||
s->in.mac->free_context(s->in.mac_ctx);
|
||||
if (s->in.comp_ctx)
|
||||
s->in.comp->decompress_cleanup(s->in.comp_ctx);
|
||||
|
||||
s->in.cipher = cipher;
|
||||
if (cipher) {
|
||||
s->in.cipher_ctx = cipher->make_context();
|
||||
cipher->setkey(s->in.cipher_ctx, ckey);
|
||||
cipher->setiv(s->in.cipher_ctx, iv);
|
||||
}
|
||||
s->in.mac = mac;
|
||||
s->in.etm_mode = etm_mode;
|
||||
if (mac) {
|
||||
s->in.mac_ctx = mac->make_context(s->in.cipher_ctx);
|
||||
mac->setkey(s->in.mac_ctx, mac_key);
|
||||
}
|
||||
|
||||
s->in.comp = compression;
|
||||
/* in_comp is always non-NULL, because no compression is
|
||||
* indicated by ssh_comp_none. So compress_init always exists, but
|
||||
* it may return a null in_comp_ctx. */
|
||||
s->in.comp_ctx = compression->decompress_init();
|
||||
|
||||
/* Clear the pending_newkeys flag, so that handle_input below will
|
||||
* start consuming the input data again. */
|
||||
s->pending_newkeys = FALSE;
|
||||
}
|
||||
|
||||
static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
|
||||
|
||||
crBegin(s->crState);
|
||||
|
||||
while (1) {
|
||||
s->maxlen = 0;
|
||||
s->length = 0;
|
||||
if (s->in.cipher)
|
||||
s->cipherblk = s->in.cipher->blksize;
|
||||
else
|
||||
s->cipherblk = 8;
|
||||
if (s->cipherblk < 8)
|
||||
s->cipherblk = 8;
|
||||
s->maclen = s->in.mac ? s->in.mac->len : 0;
|
||||
|
||||
if (s->in.cipher && (s->in.cipher->flags & SSH_CIPHER_IS_CBC) &&
|
||||
s->in.mac && !s->in.etm_mode) {
|
||||
/*
|
||||
* When dealing with a CBC-mode cipher, we want to avoid the
|
||||
* possibility of an attacker's tweaking the ciphertext stream
|
||||
* so as to cause us to feed the same block to the block
|
||||
* cipher more than once and thus leak information
|
||||
* (VU#958563). The way we do this is not to take any
|
||||
* decisions on the basis of anything we've decrypted until
|
||||
* we've verified it with a MAC. That includes the packet
|
||||
* length, so we just read data and check the MAC repeatedly,
|
||||
* and when the MAC passes, see if the length we've got is
|
||||
* plausible.
|
||||
*
|
||||
* This defence is unnecessary in OpenSSH ETM mode, because
|
||||
* the whole point of ETM mode is that the attacker can't
|
||||
* tweak the ciphertext stream at all without the MAC
|
||||
* detecting it before we decrypt anything.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Make sure we have buffer space for a maximum-size packet.
|
||||
*/
|
||||
unsigned buflimit = OUR_V2_PACKETLIMIT + s->maclen;
|
||||
if (s->bufsize < buflimit) {
|
||||
s->bufsize = buflimit;
|
||||
s->buf = sresize(s->buf, s->bufsize, unsigned char);
|
||||
}
|
||||
|
||||
/* Read an amount corresponding to the MAC. */
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
s->bpp.in_raw, s->buf, s->maclen));
|
||||
|
||||
s->packetlen = 0;
|
||||
s->in.mac->start(s->in.mac_ctx);
|
||||
s->sc_mac_bs = s->in.mac->sink(s->in.mac_ctx);
|
||||
put_uint32(s->sc_mac_bs, s->in.sequence);
|
||||
|
||||
for (;;) { /* Once around this loop per cipher block. */
|
||||
/* Read another cipher-block's worth, and tack it on to
|
||||
* the end. */
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
s->bpp.in_raw,
|
||||
s->buf + (s->packetlen + s->maclen),
|
||||
s->cipherblk));
|
||||
/* Decrypt one more block (a little further back in
|
||||
* the stream). */
|
||||
s->in.cipher->decrypt(
|
||||
s->in.cipher_ctx,
|
||||
s->buf + s->packetlen, s->cipherblk);
|
||||
|
||||
/* Feed that block to the MAC. */
|
||||
put_data(s->sc_mac_bs,
|
||||
s->buf + s->packetlen, s->cipherblk);
|
||||
s->packetlen += s->cipherblk;
|
||||
|
||||
/* See if that gives us a valid packet. */
|
||||
if (s->in.mac->verresult(
|
||||
s->in.mac_ctx, s->buf + s->packetlen) &&
|
||||
((s->len = toint(GET_32BIT(s->buf))) ==
|
||||
s->packetlen-4))
|
||||
break;
|
||||
if (s->packetlen >= (long)OUR_V2_PACKETLIMIT) {
|
||||
s->bpp.error = dupprintf(
|
||||
"No valid incoming packet found");
|
||||
crStopV;
|
||||
}
|
||||
}
|
||||
s->maxlen = s->packetlen + s->maclen;
|
||||
|
||||
/*
|
||||
* Now transfer the data into an output packet.
|
||||
*/
|
||||
s->pktin = snew_plus(PktIn, s->maxlen);
|
||||
s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
|
||||
s->pktin->refcount = 1;
|
||||
s->pktin->type = 0;
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
memcpy(s->data, s->buf, s->maxlen);
|
||||
} else if (s->in.mac && s->in.etm_mode) {
|
||||
if (s->bufsize < 4) {
|
||||
s->bufsize = 4;
|
||||
s->buf = sresize(s->buf, s->bufsize, unsigned char);
|
||||
}
|
||||
|
||||
/*
|
||||
* OpenSSH encrypt-then-MAC mode: the packet length is
|
||||
* unencrypted, unless the cipher supports length encryption.
|
||||
*/
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
s->bpp.in_raw, s->buf, 4));
|
||||
|
||||
/* Cipher supports length decryption, so do it */
|
||||
if (s->in.cipher &&
|
||||
(s->in.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
|
||||
/* Keep the packet the same though, so the MAC passes */
|
||||
unsigned char len[4];
|
||||
memcpy(len, s->buf, 4);
|
||||
s->in.cipher->decrypt_length(
|
||||
s->in.cipher_ctx, len, 4, s->in.sequence);
|
||||
s->len = toint(GET_32BIT(len));
|
||||
} else {
|
||||
s->len = toint(GET_32BIT(s->buf));
|
||||
}
|
||||
|
||||
/*
|
||||
* _Completely_ silly lengths should be stomped on before they
|
||||
* do us any more damage.
|
||||
*/
|
||||
if (s->len < 0 || s->len > (long)OUR_V2_PACKETLIMIT ||
|
||||
s->len % s->cipherblk != 0) {
|
||||
s->bpp.error = dupprintf(
|
||||
"Incoming packet length field was garbled");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
/*
|
||||
* So now we can work out the total packet length.
|
||||
*/
|
||||
s->packetlen = s->len + 4;
|
||||
|
||||
/*
|
||||
* Allocate the packet to return, now we know its length.
|
||||
*/
|
||||
s->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + s->maclen);
|
||||
s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
|
||||
s->pktin->refcount = 1;
|
||||
s->pktin->type = 0;
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
memcpy(s->data, s->buf, 4);
|
||||
|
||||
/*
|
||||
* Read the remainder of the packet.
|
||||
*/
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
s->bpp.in_raw, s->data + 4,
|
||||
s->packetlen + s->maclen - 4));
|
||||
|
||||
/*
|
||||
* Check the MAC.
|
||||
*/
|
||||
if (s->in.mac && !s->in.mac->verify(
|
||||
s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) {
|
||||
s->bpp.error = dupprintf("Incorrect MAC received on packet");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
/* Decrypt everything between the length field and the MAC. */
|
||||
if (s->in.cipher)
|
||||
s->in.cipher->decrypt(
|
||||
s->in.cipher_ctx, s->data + 4, s->packetlen - 4);
|
||||
} else {
|
||||
if (s->bufsize < s->cipherblk) {
|
||||
s->bufsize = s->cipherblk;
|
||||
s->buf = sresize(s->buf, s->bufsize, unsigned char);
|
||||
}
|
||||
|
||||
/*
|
||||
* Acquire and decrypt the first block of the packet. This will
|
||||
* contain the length and padding details.
|
||||
*/
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
s->bpp.in_raw, s->buf, s->cipherblk));
|
||||
|
||||
if (s->in.cipher)
|
||||
s->in.cipher->decrypt(
|
||||
s->in.cipher_ctx, s->buf, s->cipherblk);
|
||||
|
||||
/*
|
||||
* Now get the length figure.
|
||||
*/
|
||||
s->len = toint(GET_32BIT(s->buf));
|
||||
|
||||
/*
|
||||
* _Completely_ silly lengths should be stomped on before they
|
||||
* do us any more damage.
|
||||
*/
|
||||
if (s->len < 0 || s->len > (long)OUR_V2_PACKETLIMIT ||
|
||||
(s->len + 4) % s->cipherblk != 0) {
|
||||
s->bpp.error = dupprintf(
|
||||
"Incoming packet was garbled on decryption");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
/*
|
||||
* So now we can work out the total packet length.
|
||||
*/
|
||||
s->packetlen = s->len + 4;
|
||||
|
||||
/*
|
||||
* Allocate the packet to return, now we know its length.
|
||||
*/
|
||||
s->maxlen = s->packetlen + s->maclen;
|
||||
s->pktin = snew_plus(PktIn, s->maxlen);
|
||||
s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
|
||||
s->pktin->refcount = 1;
|
||||
s->pktin->type = 0;
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
memcpy(s->data, s->buf, s->cipherblk);
|
||||
|
||||
/*
|
||||
* Read and decrypt the remainder of the packet.
|
||||
*/
|
||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||
s->bpp.in_raw, s->data + s->cipherblk,
|
||||
s->packetlen + s->maclen - s->cipherblk));
|
||||
|
||||
/* Decrypt everything _except_ the MAC. */
|
||||
if (s->in.cipher)
|
||||
s->in.cipher->decrypt(
|
||||
s->in.cipher_ctx,
|
||||
s->data + s->cipherblk, s->packetlen - s->cipherblk);
|
||||
|
||||
/*
|
||||
* Check the MAC.
|
||||
*/
|
||||
if (s->in.mac && !s->in.mac->verify(
|
||||
s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) {
|
||||
s->bpp.error = dupprintf("Incorrect MAC received on packet");
|
||||
crStopV;
|
||||
}
|
||||
}
|
||||
/* Get and sanity-check the amount of random padding. */
|
||||
s->pad = s->data[4];
|
||||
if (s->pad < 4 || s->len - s->pad < 1) {
|
||||
s->bpp.error = dupprintf(
|
||||
"Invalid padding length on received packet");
|
||||
crStopV;
|
||||
}
|
||||
/*
|
||||
* This enables us to deduce the payload length.
|
||||
*/
|
||||
s->payload = s->len - s->pad - 1;
|
||||
|
||||
s->length = s->payload + 5;
|
||||
s->pktin->encrypted_len = s->packetlen;
|
||||
|
||||
s->pktin->sequence = s->in.sequence++;
|
||||
|
||||
s->length = s->packetlen - s->pad;
|
||||
assert(s->length >= 0);
|
||||
|
||||
/*
|
||||
* Decompress packet payload.
|
||||
*/
|
||||
{
|
||||
unsigned char *newpayload;
|
||||
int newlen;
|
||||
if (s->in.comp && s->in.comp->decompress(
|
||||
s->in.comp_ctx, s->data + 5, s->length - 5,
|
||||
&newpayload, &newlen)) {
|
||||
if (s->maxlen < newlen + 5) {
|
||||
PktIn *old_pktin = s->pktin;
|
||||
|
||||
s->maxlen = newlen + 5;
|
||||
s->pktin = snew_plus(PktIn, s->maxlen);
|
||||
*s->pktin = *old_pktin; /* structure copy */
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
|
||||
smemclr(old_pktin, s->packetlen + s->maclen);
|
||||
sfree(old_pktin);
|
||||
}
|
||||
s->length = 5 + newlen;
|
||||
memcpy(s->data + 5, newpayload, newlen);
|
||||
sfree(newpayload);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we can identify the semantic content of the packet,
|
||||
* and also the initial type byte.
|
||||
*/
|
||||
if (s->length <= 5) { /* == 5 we hope, but robustness */
|
||||
/*
|
||||
* RFC 4253 doesn't explicitly say that completely empty
|
||||
* packets with no type byte are forbidden. We handle them
|
||||
* here by giving them a type code larger than 0xFF, which
|
||||
* will be picked up at the next layer and trigger
|
||||
* SSH_MSG_UNIMPLEMENTED.
|
||||
*/
|
||||
s->pktin->type = SSH_MSG_NO_TYPE_CODE;
|
||||
s->length = 0;
|
||||
BinarySource_INIT(s->pktin, s->data + 5, 0);
|
||||
} else {
|
||||
s->pktin->type = s->data[5];
|
||||
s->length -= 6;
|
||||
BinarySource_INIT(s->pktin, s->data + 6, s->length);
|
||||
}
|
||||
|
||||
if (s->bpp.logctx) {
|
||||
logblank_t blanks[MAX_BLANKS];
|
||||
int nblanks = ssh2_censor_packet(
|
||||
s->bpp.pls, s->pktin->type, FALSE,
|
||||
make_ptrlen(s->data, s->length), blanks);
|
||||
log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type,
|
||||
ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
|
||||
s->pktin->type),
|
||||
get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks,
|
||||
&s->pktin->sequence, 0, NULL);
|
||||
}
|
||||
|
||||
pq_push(s->bpp.in_pq, s->pktin);
|
||||
|
||||
{
|
||||
int type = s->pktin->type;
|
||||
s->pktin = NULL;
|
||||
|
||||
if (type == SSH2_MSG_DISCONNECT)
|
||||
s->bpp.seen_disconnect = TRUE;
|
||||
if (type == SSH2_MSG_NEWKEYS) {
|
||||
/*
|
||||
* Mild layer violation: in this situation we must
|
||||
* suspend processing of the input byte stream until
|
||||
* the transport layer has initialised the new keys by
|
||||
* calling ssh2_bpp_new_incoming_crypto above.
|
||||
*/
|
||||
s->pending_newkeys = TRUE;
|
||||
crWaitUntilV(!s->pending_newkeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
crFinishV;
|
||||
}
|
||||
|
||||
static PktOut *ssh2_bpp_new_pktout(int pkt_type)
|
||||
{
|
||||
PktOut *pkt = ssh_new_packet();
|
||||
pkt->length = 5; /* space for packet length + padding length */
|
||||
pkt->minlen = 0;
|
||||
pkt->type = pkt_type;
|
||||
put_byte(pkt, pkt_type);
|
||||
pkt->prefix = pkt->length;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
|
||||
{
|
||||
int origlen, cipherblk, maclen, padding, unencrypted_prefix, i;
|
||||
|
||||
if (s->bpp.logctx) {
|
||||
ptrlen pktdata = make_ptrlen(pkt->data + pkt->prefix,
|
||||
pkt->length - pkt->prefix);
|
||||
logblank_t blanks[MAX_BLANKS];
|
||||
int nblanks = ssh2_censor_packet(
|
||||
s->bpp.pls, pkt->type, TRUE, pktdata, blanks);
|
||||
log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type,
|
||||
ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
|
||||
pkt->type),
|
||||
pktdata.ptr, pktdata.len, nblanks, blanks, &s->out.sequence,
|
||||
pkt->downstream_id, pkt->additional_log_text);
|
||||
}
|
||||
|
||||
cipherblk = s->out.cipher ? s->out.cipher->blksize : 8;
|
||||
cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */
|
||||
|
||||
if (s->out.comp && s->out.comp_ctx) {
|
||||
unsigned char *newpayload;
|
||||
int minlen, newlen;
|
||||
|
||||
/*
|
||||
* Compress packet payload.
|
||||
*/
|
||||
minlen = pkt->minlen;
|
||||
if (minlen) {
|
||||
/*
|
||||
* Work out how much compressed data we need (at least) to
|
||||
* make the overall packet length come to pkt->minlen.
|
||||
*/
|
||||
if (s->out.mac)
|
||||
minlen -= s->out.mac->len;
|
||||
minlen -= 8; /* length field + min padding */
|
||||
}
|
||||
|
||||
s->out.comp->compress(s->out.comp_ctx, pkt->data + 5, pkt->length - 5,
|
||||
&newpayload, &newlen, minlen);
|
||||
pkt->length = 5;
|
||||
put_data(pkt, newpayload, newlen);
|
||||
sfree(newpayload);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add padding. At least four bytes, and must also bring total
|
||||
* length (minus MAC) up to a multiple of the block size.
|
||||
* If pkt->forcepad is set, make sure the packet is at least that size
|
||||
* after padding.
|
||||
*/
|
||||
padding = 4;
|
||||
unencrypted_prefix = (s->out.mac && s->out.etm_mode) ? 4 : 0;
|
||||
padding +=
|
||||
(cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk)
|
||||
% cipherblk;
|
||||
assert(padding <= 255);
|
||||
maclen = s->out.mac ? s->out.mac->len : 0;
|
||||
origlen = pkt->length;
|
||||
for (i = 0; i < padding; i++)
|
||||
put_byte(pkt, random_byte());
|
||||
pkt->data[4] = padding;
|
||||
PUT_32BIT(pkt->data, origlen + padding - 4);
|
||||
|
||||
/* Encrypt length if the scheme requires it */
|
||||
if (s->out.cipher &&
|
||||
(s->out.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
|
||||
s->out.cipher->encrypt_length(s->out.cipher_ctx, pkt->data, 4,
|
||||
s->out.sequence);
|
||||
}
|
||||
|
||||
put_padding(pkt, maclen, 0);
|
||||
|
||||
if (s->out.mac && s->out.etm_mode) {
|
||||
/*
|
||||
* OpenSSH-defined encrypt-then-MAC protocol.
|
||||
*/
|
||||
if (s->out.cipher)
|
||||
s->out.cipher->encrypt(s->out.cipher_ctx,
|
||||
pkt->data + 4, origlen + padding - 4);
|
||||
s->out.mac->generate(s->out.mac_ctx, pkt->data, origlen + padding,
|
||||
s->out.sequence);
|
||||
} else {
|
||||
/*
|
||||
* SSH-2 standard protocol.
|
||||
*/
|
||||
if (s->out.mac)
|
||||
s->out.mac->generate(
|
||||
s->out.mac_ctx, pkt->data, origlen + padding,
|
||||
s->out.sequence);
|
||||
if (s->out.cipher)
|
||||
s->out.cipher->encrypt(s->out.cipher_ctx,
|
||||
pkt->data, origlen + padding);
|
||||
}
|
||||
|
||||
s->out.sequence++; /* whether or not we MACed */
|
||||
pkt->encrypted_len = origlen + padding;
|
||||
|
||||
}
|
||||
|
||||
static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
|
||||
{
|
||||
struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
|
||||
|
||||
if (pkt->minlen > 0 && !(s->out.comp && s->out.comp_ctx)) {
|
||||
/*
|
||||
* If we've been told to pad the packet out to a given minimum
|
||||
* length, but we're not compressing (and hence can't get the
|
||||
* compression to do the padding by pointlessly opening and
|
||||
* closing zlib blocks), then our other strategy is to precede
|
||||
* this message with an SSH_MSG_IGNORE that makes it up to the
|
||||
* right length.
|
||||
*
|
||||
* A third option in principle, and the most obviously
|
||||
* sensible, would be to set the explicit padding field in the
|
||||
* packet to more than its minimum value. Sadly, that turns
|
||||
* out to break some servers (our institutional memory thinks
|
||||
* Cisco in particular) and so we abandoned that idea shortly
|
||||
* after trying it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Calculate the length we expect the real packet to have.
|
||||
*/
|
||||
int block, length;
|
||||
PktOut *ignore_pkt;
|
||||
|
||||
block = s->out.cipher ? s->out.cipher->blksize : 0;
|
||||
if (block < 8)
|
||||
block = 8;
|
||||
length = pkt->length;
|
||||
length += 4; /* minimum 4 byte padding */
|
||||
length += block-1;
|
||||
length -= (length % block);
|
||||
if (s->out.mac)
|
||||
length += s->out.mac->len;
|
||||
|
||||
if (length < pkt->minlen) {
|
||||
/*
|
||||
* We need an ignore message. Calculate its length.
|
||||
*/
|
||||
length = pkt->minlen - length;
|
||||
|
||||
/*
|
||||
* And work backwards from that to the length of the
|
||||
* contained string.
|
||||
*/
|
||||
if (s->out.mac)
|
||||
length -= s->out.mac->len;
|
||||
length -= 8; /* length field + min padding */
|
||||
length -= 5; /* type code + string length prefix */
|
||||
|
||||
if (length < 0)
|
||||
length = 0;
|
||||
|
||||
ignore_pkt = ssh2_bpp_new_pktout(SSH2_MSG_IGNORE);
|
||||
put_uint32(ignore_pkt, length);
|
||||
while (length-- > 0)
|
||||
put_byte(ignore_pkt, random_byte());
|
||||
ssh2_bpp_format_packet_inner(s, ignore_pkt);
|
||||
bufchain_add(s->bpp.out_raw, ignore_pkt->data, ignore_pkt->length);
|
||||
ssh_free_pktout(ignore_pkt);
|
||||
}
|
||||
}
|
||||
|
||||
ssh2_bpp_format_packet_inner(s, pkt);
|
||||
bufchain_add(s->bpp.out_raw, pkt->data, pkt->length);
|
||||
|
||||
ssh_free_pktout(pkt);
|
||||
}
|
||||
|
||||
#ifdef MPEXT
|
||||
const struct ssh2_cipher * ssh2_bpp_get_cscipher(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
return FROMFIELD(bpp, struct ssh2_bpp_state, bpp)->out.cipher;
|
||||
}
|
||||
|
||||
const struct ssh2_cipher * ssh2_bpp_get_sccipher(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
return FROMFIELD(bpp, struct ssh2_bpp_state, bpp)->in.cipher;
|
||||
}
|
||||
|
||||
const struct ssh_compress * ssh2_bpp_get_cscomp(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
return FROMFIELD(bpp, struct ssh2_bpp_state, bpp)->out.comp;
|
||||
}
|
||||
|
||||
const struct ssh_compress * ssh2_bpp_get_sccomp(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
return FROMFIELD(bpp, struct ssh2_bpp_state, bpp)->in.comp;
|
||||
}
|
||||
|
||||
#endif
|
||||
107
source/putty/ssh2censor.c
vendored
Normal file
107
source/putty/ssh2censor.c
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Packet-censoring code for SSH-2, used to identify sensitive fields
|
||||
* like passwords so that the logging system can avoid writing them
|
||||
* into log files.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
int ssh2_censor_packet(
|
||||
const PacketLogSettings *pls, int type, int sender_is_client,
|
||||
ptrlen pkt, logblank_t *blanks)
|
||||
{
|
||||
int nblanks = 0;
|
||||
ptrlen str;
|
||||
BinarySource src[1];
|
||||
|
||||
BinarySource_BARE_INIT(src, pkt.ptr, pkt.len);
|
||||
|
||||
if (pls->omit_data &&
|
||||
(type == SSH2_MSG_CHANNEL_DATA ||
|
||||
type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) {
|
||||
/* "Session data" packets - omit the data string. */
|
||||
get_uint32(src); /* skip channel id */
|
||||
if (type == SSH2_MSG_CHANNEL_EXTENDED_DATA)
|
||||
get_uint32(src); /* skip extended data type */
|
||||
str = get_string(src);
|
||||
if (!get_err(src)) {
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = src->pos - str.len;
|
||||
blanks[nblanks].type = PKTLOG_OMIT;
|
||||
blanks[nblanks].len = str.len;
|
||||
nblanks++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sender_is_client && pls->omit_passwords) {
|
||||
if (type == SSH2_MSG_USERAUTH_REQUEST) {
|
||||
/* If this is a password packet, blank the password(s). */
|
||||
get_string(src); /* username */
|
||||
get_string(src); /* service name */
|
||||
str = get_string(src); /* auth method */
|
||||
if (ptrlen_eq_string(str, "password")) {
|
||||
get_bool(src);
|
||||
/* Blank the password field. */
|
||||
str = get_string(src);
|
||||
if (!get_err(src)) {
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = src->pos - str.len;
|
||||
blanks[nblanks].type = PKTLOG_BLANK;
|
||||
blanks[nblanks].len = str.len;
|
||||
nblanks++;
|
||||
/* If there's another password field beyond it
|
||||
* (change of password), blank that too. */
|
||||
str = get_string(src);
|
||||
if (!get_err(src))
|
||||
blanks[nblanks-1].len =
|
||||
src->pos - blanks[nblanks].offset;
|
||||
}
|
||||
}
|
||||
} else if (pls->actx == SSH2_PKTCTX_KBDINTER &&
|
||||
type == SSH2_MSG_USERAUTH_INFO_RESPONSE) {
|
||||
/* If this is a keyboard-interactive response packet,
|
||||
* blank the responses. */
|
||||
get_uint32(src);
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = src->pos;
|
||||
blanks[nblanks].type = PKTLOG_BLANK;
|
||||
do {
|
||||
str = get_string(src);
|
||||
} while (!get_err(src));
|
||||
blanks[nblanks].len = src->pos - blanks[nblanks].offset;
|
||||
nblanks++;
|
||||
} else if (type == SSH2_MSG_CHANNEL_REQUEST) {
|
||||
/*
|
||||
* If this is an X forwarding request packet, blank the
|
||||
* fake auth data.
|
||||
*
|
||||
* Note that while we blank the X authentication data
|
||||
* here, we don't take any special action to blank the
|
||||
* start of an X11 channel, so using MIT-MAGIC-COOKIE-1
|
||||
* and actually opening an X connection without having
|
||||
* session blanking enabled is likely to leak your cookie
|
||||
* into the log.
|
||||
*/
|
||||
get_uint32(src);
|
||||
str = get_string(src);
|
||||
if (ptrlen_eq_string(str, "x11-req")) {
|
||||
get_bool(src);
|
||||
get_bool(src);
|
||||
get_string(src);
|
||||
str = get_string(src);
|
||||
if (!get_err(src)) {
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = src->pos - str.len;
|
||||
blanks[nblanks].type = PKTLOG_BLANK;
|
||||
blanks[nblanks].len = str.len;
|
||||
nblanks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nblanks;
|
||||
}
|
||||
1296
source/putty/sshaes.c
vendored
1296
source/putty/sshaes.c
vendored
File diff suppressed because it is too large
Load Diff
9
source/putty/ssharcf.c
vendored
9
source/putty/ssharcf.c
vendored
@@ -11,8 +11,9 @@ typedef struct {
|
||||
unsigned char i, j, s[256];
|
||||
} ArcfourContext;
|
||||
|
||||
static void arcfour_block(void *handle, unsigned char *blk, int len)
|
||||
static void arcfour_block(void *handle, void *vblk, int len)
|
||||
{
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
ArcfourContext *ctx = (ArcfourContext *)handle;
|
||||
unsigned k;
|
||||
unsigned char tmp, i, j, *s;
|
||||
@@ -79,21 +80,21 @@ static void arcfour_stir(ArcfourContext *ctx)
|
||||
sfree(junk);
|
||||
}
|
||||
|
||||
static void arcfour128_key(void *handle, unsigned char *key)
|
||||
static void arcfour128_key(void *handle, const void *key)
|
||||
{
|
||||
ArcfourContext *ctx = (ArcfourContext *)handle;
|
||||
arcfour_setkey(ctx, key, 16);
|
||||
arcfour_stir(ctx);
|
||||
}
|
||||
|
||||
static void arcfour256_key(void *handle, unsigned char *key)
|
||||
static void arcfour256_key(void *handle, const void *key)
|
||||
{
|
||||
ArcfourContext *ctx = (ArcfourContext *)handle;
|
||||
arcfour_setkey(ctx, key, 32);
|
||||
arcfour_stir(ctx);
|
||||
}
|
||||
|
||||
static void arcfour_iv(void *handle, unsigned char *key)
|
||||
static void arcfour_iv(void *handle, const void *iv)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
9
source/putty/sshbcrypt.c
vendored
9
source/putty/sshbcrypt.c
vendored
@@ -56,16 +56,13 @@ void bcrypt_genblock(int counter,
|
||||
{
|
||||
SHA512_State shastate;
|
||||
unsigned char hashed_salt[64];
|
||||
unsigned char countbuf[4];
|
||||
|
||||
/* Hash the input salt with the counter value optionally suffixed
|
||||
* to get our real 32-byte salt */
|
||||
SHA512_Init(&shastate);
|
||||
SHA512_Bytes(&shastate, salt, saltbytes);
|
||||
if (counter) {
|
||||
PUT_32BIT_MSB_FIRST(countbuf, counter);
|
||||
SHA512_Bytes(&shastate, countbuf, 4);
|
||||
}
|
||||
put_data(&shastate, salt, saltbytes);
|
||||
if (counter)
|
||||
put_uint32(&shastate, counter);
|
||||
SHA512_Final(&shastate, hashed_salt);
|
||||
|
||||
bcrypt_hash(hashed_passphrase, 64, hashed_salt, 64, output);
|
||||
|
||||
40
source/putty/sshblowf.c
vendored
40
source/putty/sshblowf.c
vendored
@@ -300,7 +300,7 @@ static void blowfish_decrypt(word32 xL, word32 xR, word32 * output,
|
||||
}
|
||||
|
||||
static void blowfish_lsb_encrypt_cbc(unsigned char *blk, int len,
|
||||
BlowfishContext * ctx)
|
||||
BlowfishContext * ctx)
|
||||
{
|
||||
word32 xL, xR, out[2], iv0, iv1;
|
||||
|
||||
@@ -327,9 +327,9 @@ static void blowfish_lsb_encrypt_cbc(unsigned char *blk, int len,
|
||||
ctx->iv1 = iv1;
|
||||
}
|
||||
|
||||
void blowfish_lsb_encrypt_ecb(unsigned char *blk, int len,
|
||||
BlowfishContext * ctx)
|
||||
void blowfish_lsb_encrypt_ecb(void *vblk, int len, BlowfishContext * ctx)
|
||||
{
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
word32 xL, xR, out[2];
|
||||
|
||||
assert((len & 7) == 0);
|
||||
@@ -472,9 +472,11 @@ void blowfish_initkey(BlowfishContext *ctx)
|
||||
}
|
||||
|
||||
void blowfish_expandkey(BlowfishContext * ctx,
|
||||
const unsigned char *key, short keybytes,
|
||||
const unsigned char *salt, short saltbytes)
|
||||
const void *vkey, short keybytes,
|
||||
const void *vsalt, short saltbytes)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
const unsigned char *salt = (const unsigned char *)vsalt;
|
||||
word32 *S0 = ctx->S0;
|
||||
word32 *S1 = ctx->S1;
|
||||
word32 *S2 = ctx->S2;
|
||||
@@ -570,26 +572,27 @@ void blowfish_free_context(void *handle)
|
||||
sfree(handle);
|
||||
}
|
||||
|
||||
static void blowfish_key(void *handle, unsigned char *key)
|
||||
static void blowfish_key(void *handle, const void *key)
|
||||
{
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
blowfish_setkey(ctx, key, 16);
|
||||
}
|
||||
|
||||
static void blowfish256_key(void *handle, unsigned char *key)
|
||||
static void blowfish256_key(void *handle, const void *key)
|
||||
{
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
blowfish_setkey(ctx, key, 32);
|
||||
}
|
||||
|
||||
static void blowfish_iv(void *handle, unsigned char *key)
|
||||
static void blowfish_iv(void *handle, const void *viv)
|
||||
{
|
||||
const unsigned char *iv = (const unsigned char *)viv;
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
ctx->iv0 = GET_32BIT_MSB_FIRST(key);
|
||||
ctx->iv1 = GET_32BIT_MSB_FIRST(key + 4);
|
||||
ctx->iv0 = GET_32BIT_MSB_FIRST(iv);
|
||||
ctx->iv1 = GET_32BIT_MSB_FIRST(iv + 4);
|
||||
}
|
||||
|
||||
static void blowfish_sesskey(void *handle, unsigned char *key)
|
||||
static void blowfish_sesskey(void *handle, const void *key)
|
||||
{
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
blowfish_setkey(ctx, key, SSH_SESSION_KEY_LENGTH);
|
||||
@@ -598,36 +601,31 @@ static void blowfish_sesskey(void *handle, unsigned char *key)
|
||||
ctx[1] = ctx[0]; /* structure copy */
|
||||
}
|
||||
|
||||
static void blowfish_ssh1_encrypt_blk(void *handle, unsigned char *blk,
|
||||
int len)
|
||||
static void blowfish_ssh1_encrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
blowfish_lsb_encrypt_cbc(blk, len, ctx);
|
||||
}
|
||||
|
||||
static void blowfish_ssh1_decrypt_blk(void *handle, unsigned char *blk,
|
||||
int len)
|
||||
static void blowfish_ssh1_decrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
blowfish_lsb_decrypt_cbc(blk, len, ctx+1);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_encrypt_blk(void *handle, unsigned char *blk,
|
||||
int len)
|
||||
static void blowfish_ssh2_encrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
blowfish_msb_encrypt_cbc(blk, len, ctx);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_decrypt_blk(void *handle, unsigned char *blk,
|
||||
int len)
|
||||
static void blowfish_ssh2_decrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
blowfish_msb_decrypt_cbc(blk, len, ctx);
|
||||
}
|
||||
|
||||
static void blowfish_ssh2_sdctr(void *handle, unsigned char *blk,
|
||||
int len)
|
||||
static void blowfish_ssh2_sdctr(void *handle, void *blk, int len)
|
||||
{
|
||||
BlowfishContext *ctx = (BlowfishContext *)handle;
|
||||
blowfish_msb_sdctr(blk, len, ctx);
|
||||
|
||||
7
source/putty/sshblowf.h
vendored
7
source/putty/sshblowf.h
vendored
@@ -9,7 +9,6 @@ void *blowfish_make_context(void);
|
||||
void blowfish_free_context(void *handle);
|
||||
void blowfish_initkey(BlowfishContext *ctx);
|
||||
void blowfish_expandkey(BlowfishContext *ctx,
|
||||
const unsigned char *key, short keybytes,
|
||||
const unsigned char *salt, short saltbytes);
|
||||
void blowfish_lsb_encrypt_ecb(unsigned char *blk, int len,
|
||||
BlowfishContext *ctx);
|
||||
const void *key, short keybytes,
|
||||
const void *salt, short saltbytes);
|
||||
void blowfish_lsb_encrypt_ecb(void *blk, int len, BlowfishContext *ctx);
|
||||
|
||||
117
source/putty/sshbn.c
vendored
117
source/putty/sshbn.c
vendored
@@ -17,6 +17,7 @@
|
||||
typedef BignumInt *Bignum;
|
||||
|
||||
#include "ssh.h"
|
||||
#include "marshal.h"
|
||||
|
||||
BignumInt bnZero[1] = { 0 };
|
||||
BignumInt bnOne[2] = { 1, 1 };
|
||||
@@ -1403,8 +1404,9 @@ void decbn(Bignum bn)
|
||||
bn[i]--;
|
||||
}
|
||||
|
||||
Bignum bignum_from_bytes(const unsigned char *data, int nbytes)
|
||||
Bignum bignum_from_bytes(const void *vdata, int nbytes)
|
||||
{
|
||||
const unsigned char *data = (const unsigned char *)vdata;
|
||||
Bignum result;
|
||||
int w, i;
|
||||
|
||||
@@ -1425,8 +1427,9 @@ Bignum bignum_from_bytes(const unsigned char *data, int nbytes)
|
||||
return result;
|
||||
}
|
||||
|
||||
Bignum bignum_from_bytes_le(const unsigned char *data, int nbytes)
|
||||
Bignum bignum_from_bytes_le(const void *vdata, int nbytes)
|
||||
{
|
||||
const unsigned char *data = (const unsigned char *)vdata;
|
||||
Bignum result;
|
||||
int w, i;
|
||||
|
||||
@@ -1506,36 +1509,7 @@ Bignum bignum_random_in_range(const Bignum lower, const Bignum upper)
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an SSH-1-format bignum from a data buffer. Return the number
|
||||
* of bytes consumed, or -1 if there wasn't enough data.
|
||||
*/
|
||||
int ssh1_read_bignum(const unsigned char *data, int len, Bignum * result)
|
||||
{
|
||||
const unsigned char *p = data;
|
||||
int i;
|
||||
int w, b;
|
||||
|
||||
if (len < 2)
|
||||
return -1;
|
||||
|
||||
w = 0;
|
||||
for (i = 0; i < 2; i++)
|
||||
w = (w << 8) + *p++;
|
||||
b = (w + 7) / 8; /* bits -> bytes */
|
||||
|
||||
if (len < b+2)
|
||||
return -1;
|
||||
|
||||
if (!result) /* just return length */
|
||||
return b + 2;
|
||||
|
||||
*result = bignum_from_bytes(p, b);
|
||||
|
||||
return p + b - data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the bit count of a bignum, for SSH-1 encoding.
|
||||
* Return the bit count of a bignum.
|
||||
*/
|
||||
int bignum_bitcount(Bignum bn)
|
||||
{
|
||||
@@ -1545,22 +1519,6 @@ int bignum_bitcount(Bignum bn)
|
||||
return bitcount + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the byte length of a bignum when SSH-1 encoded.
|
||||
*/
|
||||
int ssh1_bignum_length(Bignum bn)
|
||||
{
|
||||
return 2 + (bignum_bitcount(bn) + 7) / 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the byte length of a bignum when SSH-2 encoded.
|
||||
*/
|
||||
int ssh2_bignum_length(Bignum bn)
|
||||
{
|
||||
return 4 + (bignum_bitcount(bn) + 8) / 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a byte from a bignum; 0 is least significant, etc.
|
||||
*/
|
||||
@@ -1601,22 +1559,59 @@ void bignum_set_bit(Bignum bn, int bitnum, int value)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a SSH-1-format bignum into a buffer. It is assumed the
|
||||
* buffer is big enough. Returns the number of bytes used.
|
||||
*/
|
||||
int ssh1_write_bignum(void *data, Bignum bn)
|
||||
void BinarySink_put_mp_ssh1(BinarySink *bs, Bignum bn)
|
||||
{
|
||||
unsigned char *p = data;
|
||||
int len = ssh1_bignum_length(bn);
|
||||
int bits = bignum_bitcount(bn);
|
||||
int bytes = (bits + 7) / 8;
|
||||
int i;
|
||||
int bitc = bignum_bitcount(bn);
|
||||
|
||||
*p++ = (bitc >> 8) & 0xFF;
|
||||
*p++ = (bitc) & 0xFF;
|
||||
for (i = len - 2; i--;)
|
||||
*p++ = bignum_byte(bn, i);
|
||||
return len;
|
||||
put_uint16(bs, bits);
|
||||
for (i = bytes; i--;)
|
||||
put_byte(bs, bignum_byte(bn, i));
|
||||
}
|
||||
|
||||
void BinarySink_put_mp_ssh2(BinarySink *bs, Bignum bn)
|
||||
{
|
||||
int bytes = (bignum_bitcount(bn) + 8) / 8;
|
||||
int i;
|
||||
|
||||
put_uint32(bs, bytes);
|
||||
for (i = bytes; i--;)
|
||||
put_byte(bs, bignum_byte(bn, i));
|
||||
}
|
||||
|
||||
Bignum BinarySource_get_mp_ssh1(BinarySource *src)
|
||||
{
|
||||
unsigned bitc = get_uint16(src);
|
||||
ptrlen bytes = get_data(src, (bitc + 7) / 8);
|
||||
if (get_err(src)) {
|
||||
return bignum_from_long(0);
|
||||
} else {
|
||||
Bignum toret = bignum_from_bytes(bytes.ptr, bytes.len);
|
||||
if (bignum_bitcount(toret) != bitc) {
|
||||
src->err = BSE_INVALID;
|
||||
freebn(toret);
|
||||
toret = bignum_from_long(0);
|
||||
}
|
||||
return toret;
|
||||
}
|
||||
}
|
||||
|
||||
Bignum BinarySource_get_mp_ssh2(BinarySource *src)
|
||||
{
|
||||
ptrlen bytes = get_string(src);
|
||||
if (get_err(src)) {
|
||||
return bignum_from_long(0);
|
||||
} else {
|
||||
const unsigned char *p = bytes.ptr;
|
||||
if ((bytes.len > 0 &&
|
||||
((p[0] & 0x80) ||
|
||||
(p[0] == 0 && (bytes.len <= 1 || !(p[1] & 0x80)))))) {
|
||||
src->err = BSE_INVALID;
|
||||
return bignum_from_long(0);
|
||||
}
|
||||
return bignum_from_bytes(bytes.ptr, bytes.len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
62
source/putty/sshbpp.h
vendored
Normal file
62
source/putty/sshbpp.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Abstraction of the binary packet protocols used in SSH.
|
||||
*/
|
||||
|
||||
#ifndef PUTTY_SSHBPP_H
|
||||
#define PUTTY_SSHBPP_H
|
||||
|
||||
typedef struct BinaryPacketProtocol BinaryPacketProtocol;
|
||||
|
||||
struct BinaryPacketProtocolVtable {
|
||||
void (*free)(BinaryPacketProtocol *);
|
||||
void (*handle_input)(BinaryPacketProtocol *);
|
||||
PktOut *(*new_pktout)(int type);
|
||||
void (*format_packet)(BinaryPacketProtocol *, PktOut *);
|
||||
};
|
||||
|
||||
struct BinaryPacketProtocol {
|
||||
const struct BinaryPacketProtocolVtable *vt;
|
||||
bufchain *in_raw, *out_raw;
|
||||
PacketQueue *in_pq;
|
||||
PacketLogSettings *pls;
|
||||
void *logctx;
|
||||
|
||||
int seen_disconnect;
|
||||
char *error;
|
||||
};
|
||||
|
||||
#define ssh_bpp_free(bpp) ((bpp)->vt->free(bpp))
|
||||
#define ssh_bpp_handle_input(bpp) ((bpp)->vt->handle_input(bpp))
|
||||
#define ssh_bpp_new_pktout(bpp, type) ((bpp)->vt->new_pktout(type))
|
||||
#define ssh_bpp_format_packet(bpp, pkt) ((bpp)->vt->format_packet(bpp, pkt))
|
||||
|
||||
BinaryPacketProtocol *ssh1_bpp_new(void);
|
||||
void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
|
||||
const struct ssh_cipher *cipher,
|
||||
const void *session_key);
|
||||
void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp);
|
||||
|
||||
BinaryPacketProtocol *ssh2_bpp_new(void);
|
||||
void ssh2_bpp_new_outgoing_crypto(
|
||||
BinaryPacketProtocol *bpp,
|
||||
const struct ssh2_cipher *cipher, const void *ckey, const void *iv,
|
||||
const struct ssh_mac *mac, int etm_mode, const void *mac_key,
|
||||
const struct ssh_compress *compression);
|
||||
void ssh2_bpp_new_incoming_crypto(
|
||||
BinaryPacketProtocol *bpp,
|
||||
const struct ssh2_cipher *cipher, const void *ckey, const void *iv,
|
||||
const struct ssh_mac *mac, int etm_mode, const void *mac_key,
|
||||
const struct ssh_compress *compression);
|
||||
|
||||
BinaryPacketProtocol *ssh2_bare_bpp_new(void);
|
||||
|
||||
#ifdef MPEXT
|
||||
const struct ssh_cipher * ssh1_bpp_get_cipher(BinaryPacketProtocol *bpp);
|
||||
int ssh1_bpp_get_compressing(BinaryPacketProtocol *bpp);
|
||||
const struct ssh2_cipher * ssh2_bpp_get_cscipher(BinaryPacketProtocol *bpp);
|
||||
const struct ssh2_cipher * ssh2_bpp_get_sccipher(BinaryPacketProtocol *bpp);
|
||||
const struct ssh_compress * ssh2_bpp_get_cscomp(BinaryPacketProtocol *bpp);
|
||||
const struct ssh_compress * ssh2_bpp_get_sccomp(BinaryPacketProtocol *bpp);
|
||||
#endif
|
||||
|
||||
#endif /* PUTTY_SSHBPP_H */
|
||||
59
source/putty/sshccp.c
vendored
59
source/putty/sshccp.c
vendored
@@ -864,6 +864,8 @@ struct ccp_context {
|
||||
unsigned char mac_iv[8];
|
||||
|
||||
struct poly1305 mac;
|
||||
|
||||
BinarySink_IMPLEMENTATION;
|
||||
};
|
||||
|
||||
static void *poly_make_context(void *ctx)
|
||||
@@ -876,7 +878,7 @@ static void poly_free_context(void *ctx)
|
||||
/* Not allocated, just forwarded, no need to free */
|
||||
}
|
||||
|
||||
static void poly_setkey(void *ctx, unsigned char *key)
|
||||
static void poly_setkey(void *ctx, const void *key)
|
||||
{
|
||||
/* Uses the same context as ChaCha20, so ignore */
|
||||
}
|
||||
@@ -890,9 +892,10 @@ static void poly_start(void *handle)
|
||||
poly1305_init(&ctx->mac);
|
||||
}
|
||||
|
||||
static void poly_bytes(void *handle, unsigned char const *blk, int len)
|
||||
static void poly_BinarySink_write(BinarySink *bs, const void *blkv, size_t len)
|
||||
{
|
||||
struct ccp_context *ctx = (struct ccp_context *)handle;
|
||||
struct ccp_context *ctx = BinarySink_DOWNCAST(bs, struct ccp_context);
|
||||
const unsigned char *blk = (const unsigned char *)blkv;
|
||||
|
||||
/* First 4 bytes are the IV */
|
||||
while (ctx->mac_initialised < 4 && len) {
|
||||
@@ -922,6 +925,12 @@ static void poly_bytes(void *handle, unsigned char const *blk, int len)
|
||||
}
|
||||
}
|
||||
|
||||
static BinarySink *poly_sink(void *handle)
|
||||
{
|
||||
struct ccp_context *ctx = (struct ccp_context *)handle;
|
||||
return BinarySink_UPCAST(ctx);
|
||||
}
|
||||
|
||||
static void poly_genresult(void *handle, unsigned char *blk)
|
||||
{
|
||||
struct ccp_context *ctx = (struct ccp_context *)handle;
|
||||
@@ -939,25 +948,27 @@ static int poly_verresult(void *handle, unsigned char const *blk)
|
||||
}
|
||||
|
||||
/* The generic poly operation used before generate and verify */
|
||||
static void poly_op(void *handle, unsigned char *blk, int len, unsigned long seq)
|
||||
static void poly_op(void *handle, const unsigned char *blk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
unsigned char iv[4];
|
||||
poly_start(handle);
|
||||
PUT_32BIT_MSB_FIRST(iv, seq);
|
||||
/* poly_bytes expects the first 4 bytes to be the IV */
|
||||
poly_bytes(handle, iv, 4);
|
||||
smemclr(iv, sizeof(iv));
|
||||
poly_bytes(handle, blk, len);
|
||||
struct ccp_context *ctx = (struct ccp_context *)handle;
|
||||
poly_start(ctx);
|
||||
/* the data receiver expects the first 4 bytes to be the IV */
|
||||
put_uint32(ctx, seq);
|
||||
put_data(ctx, blk, len);
|
||||
}
|
||||
|
||||
static void poly_generate(void *handle, unsigned char *blk, int len, unsigned long seq)
|
||||
static void poly_generate(void *handle, void *vblk, int len, unsigned long seq)
|
||||
{
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
poly_op(handle, blk, len, seq);
|
||||
poly_genresult(handle, blk+len);
|
||||
}
|
||||
|
||||
static int poly_verify(void *handle, unsigned char *blk, int len, unsigned long seq)
|
||||
static int poly_verify(void *handle, const void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
const unsigned char *blk = (const unsigned char *)vblk;
|
||||
poly_op(handle, blk, len, seq);
|
||||
return poly_verresult(handle, blk+len);
|
||||
}
|
||||
@@ -970,7 +981,7 @@ static const struct ssh_mac ssh2_poly1305 = {
|
||||
poly_generate, poly_verify,
|
||||
|
||||
/* partial-packet operations */
|
||||
poly_start, poly_bytes, poly_genresult, poly_verresult,
|
||||
poly_start, poly_sink, poly_genresult, poly_verresult,
|
||||
|
||||
"", "", /* Not selectable individually, just part of ChaCha20-Poly1305 */
|
||||
16, 0, "Poly1305"
|
||||
@@ -979,9 +990,8 @@ static const struct ssh_mac ssh2_poly1305 = {
|
||||
static void *ccp_make_context(void)
|
||||
{
|
||||
struct ccp_context *ctx = snew(struct ccp_context);
|
||||
if (ctx) {
|
||||
poly1305_init(&ctx->mac);
|
||||
}
|
||||
BinarySink_INIT(ctx, poly_BinarySink_write);
|
||||
poly1305_init(&ctx->mac);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -994,14 +1004,15 @@ static void ccp_free_context(void *vctx)
|
||||
sfree(ctx);
|
||||
}
|
||||
|
||||
static void ccp_iv(void *vctx, unsigned char *iv)
|
||||
static void ccp_iv(void *vctx, const void *iv)
|
||||
{
|
||||
/* struct ccp_context *ctx = (struct ccp_context *)vctx; */
|
||||
/* IV is set based on the sequence number */
|
||||
}
|
||||
|
||||
static void ccp_key(void *vctx, unsigned char *key)
|
||||
static void ccp_key(void *vctx, const void *vkey)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
struct ccp_context *ctx = (struct ccp_context *)vctx;
|
||||
/* Initialise the a_cipher (for decrypting lengths) with the first 256 bits */
|
||||
chacha20_key(&ctx->a_cipher, key + 32);
|
||||
@@ -1009,19 +1020,19 @@ static void ccp_key(void *vctx, unsigned char *key)
|
||||
chacha20_key(&ctx->b_cipher, key);
|
||||
}
|
||||
|
||||
static void ccp_encrypt(void *vctx, unsigned char *blk, int len)
|
||||
static void ccp_encrypt(void *vctx, void *blk, int len)
|
||||
{
|
||||
struct ccp_context *ctx = (struct ccp_context *)vctx;
|
||||
chacha20_encrypt(&ctx->b_cipher, blk, len);
|
||||
}
|
||||
|
||||
static void ccp_decrypt(void *vctx, unsigned char *blk, int len)
|
||||
static void ccp_decrypt(void *vctx, void *blk, int len)
|
||||
{
|
||||
struct ccp_context *ctx = (struct ccp_context *)vctx;
|
||||
chacha20_decrypt(&ctx->b_cipher, blk, len);
|
||||
}
|
||||
|
||||
static void ccp_length_op(struct ccp_context *ctx, unsigned char *blk, int len,
|
||||
static void ccp_length_op(struct ccp_context *ctx, void *blk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
unsigned char iv[8];
|
||||
@@ -1038,7 +1049,7 @@ static void ccp_length_op(struct ccp_context *ctx, unsigned char *blk, int len,
|
||||
smemclr(iv, sizeof(iv));
|
||||
}
|
||||
|
||||
static void ccp_encrypt_length(void *vctx, unsigned char *blk, int len,
|
||||
static void ccp_encrypt_length(void *vctx, void *blk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
struct ccp_context *ctx = (struct ccp_context *)vctx;
|
||||
@@ -1046,7 +1057,7 @@ static void ccp_encrypt_length(void *vctx, unsigned char *blk, int len,
|
||||
chacha20_encrypt(&ctx->a_cipher, blk, len);
|
||||
}
|
||||
|
||||
static void ccp_decrypt_length(void *vctx, unsigned char *blk, int len,
|
||||
static void ccp_decrypt_length(void *vctx, void *blk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
struct ccp_context *ctx = (struct ccp_context *)vctx;
|
||||
|
||||
54
source/putty/sshcr.h
vendored
Normal file
54
source/putty/sshcr.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Coroutine mechanics used in PuTTY's SSH code.
|
||||
*/
|
||||
|
||||
#ifndef PUTTY_SSHCR_H
|
||||
#define PUTTY_SSHCR_H
|
||||
|
||||
/*
|
||||
* If these macros look impenetrable to you, you might find it helpful
|
||||
* to read
|
||||
*
|
||||
* https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
|
||||
*
|
||||
* which explains the theory behind these macros.
|
||||
*
|
||||
* In particular, if you are getting `case expression not constant'
|
||||
* errors when building with MS Visual Studio, this is because MS's
|
||||
* Edit and Continue debugging feature causes their compiler to
|
||||
* violate ANSI C. To disable Edit and Continue debugging:
|
||||
*
|
||||
* - right-click ssh.c in the FileView
|
||||
* - click Settings
|
||||
* - select the C/C++ tab and the General category
|
||||
* - under `Debug info:', select anything _other_ than `Program
|
||||
* Database for Edit and Continue'.
|
||||
*/
|
||||
|
||||
#define crBegin(v) { int *crLine = &v; switch(v) { case 0:;
|
||||
#define crBeginState crBegin(s->crLine)
|
||||
#define crStateP(t, v) \
|
||||
struct t *s; \
|
||||
if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; } \
|
||||
s = (v);
|
||||
#define crState(t) crStateP(t, ssh->t)
|
||||
#define crFinish(z) } *crLine = 0; return (z); }
|
||||
#define crFinishV } *crLine = 0; return; }
|
||||
#define crFinishFree(z) } sfree(s); return (z); }
|
||||
#define crFinishFreeV } sfree(s); return; }
|
||||
#define crReturn(z) \
|
||||
do {\
|
||||
*crLine =__LINE__; return (z); case __LINE__:;\
|
||||
} while (0)
|
||||
#define crReturnV \
|
||||
do {\
|
||||
*crLine=__LINE__; return; case __LINE__:;\
|
||||
} while (0)
|
||||
#define crStop(z) do{ *crLine = 0; return (z); }while(0)
|
||||
#define crStopV do{ *crLine = 0; return; }while(0)
|
||||
#define crWaitUntil(c) do { crReturn(0); } while (!(c))
|
||||
#define crWaitUntilV(c) do { crReturnV; } while (!(c))
|
||||
#define crMaybeWaitUntil(c) do { while (!(c)) crReturn(0); } while (0)
|
||||
#define crMaybeWaitUntilV(c) do { while (!(c)) crReturnV; } while (0)
|
||||
|
||||
#endif /* PUTTY_SSHCR_H */
|
||||
66
source/putty/sshdes.c
vendored
66
source/putty/sshdes.c
vendored
@@ -774,8 +774,9 @@ static void des3_free_context(void *handle) /* used for both 3DES and DES */
|
||||
sfree(handle);
|
||||
}
|
||||
|
||||
static void des3_key(void *handle, unsigned char *key)
|
||||
static void des3_key(void *handle, const void *vkey)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &keys[0]);
|
||||
@@ -785,71 +786,75 @@ static void des3_key(void *handle, unsigned char *key)
|
||||
GET_32BIT_MSB_FIRST(key + 20), &keys[2]);
|
||||
}
|
||||
|
||||
static void des3_iv(void *handle, unsigned char *key)
|
||||
static void des3_iv(void *handle, const void *viv)
|
||||
{
|
||||
const unsigned char *iv = (const unsigned char *)viv;
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
keys[0].iv0 = GET_32BIT_MSB_FIRST(key);
|
||||
keys[0].iv1 = GET_32BIT_MSB_FIRST(key + 4);
|
||||
keys[0].iv0 = GET_32BIT_MSB_FIRST(iv);
|
||||
keys[0].iv1 = GET_32BIT_MSB_FIRST(iv + 4);
|
||||
}
|
||||
|
||||
static void des_key(void *handle, unsigned char *key)
|
||||
static void des_key(void *handle, const void *vkey)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &keys[0]);
|
||||
}
|
||||
|
||||
static void des3_sesskey(void *handle, unsigned char *key)
|
||||
static void des3_sesskey(void *handle, const void *key)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des3_key(keys, key);
|
||||
des3_key(keys+3, key);
|
||||
}
|
||||
|
||||
static void des3_encrypt_blk(void *handle, unsigned char *blk, int len)
|
||||
static void des3_encrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_3cbc_encrypt(blk, len, keys);
|
||||
}
|
||||
|
||||
static void des3_decrypt_blk(void *handle, unsigned char *blk, int len)
|
||||
static void des3_decrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_3cbc_decrypt(blk, len, keys+3);
|
||||
}
|
||||
|
||||
static void des3_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len)
|
||||
static void des3_ssh2_encrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_cbc3_encrypt(blk, len, keys);
|
||||
}
|
||||
|
||||
static void des3_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len)
|
||||
static void des3_ssh2_decrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_cbc3_decrypt(blk, len, keys);
|
||||
}
|
||||
|
||||
static void des3_ssh2_sdctr(void *handle, unsigned char *blk, int len)
|
||||
static void des3_ssh2_sdctr(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_sdctr3(blk, len, keys);
|
||||
}
|
||||
|
||||
static void des_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len)
|
||||
static void des_ssh2_encrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_cbc_encrypt(blk, len, keys);
|
||||
}
|
||||
|
||||
static void des_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len)
|
||||
static void des_ssh2_decrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_cbc_decrypt(blk, len, keys);
|
||||
}
|
||||
|
||||
void des3_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len)
|
||||
void des3_decrypt_pubkey(const void *vkey, void *vblk, int len)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
DESContext ourkeys[3];
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]);
|
||||
@@ -861,8 +866,10 @@ void des3_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len)
|
||||
smemclr(ourkeys, sizeof(ourkeys));
|
||||
}
|
||||
|
||||
void des3_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len)
|
||||
void des3_encrypt_pubkey(const void *vkey, void *vblk, int len)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
DESContext ourkeys[3];
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]);
|
||||
@@ -874,9 +881,12 @@ void des3_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len)
|
||||
smemclr(ourkeys, sizeof(ourkeys));
|
||||
}
|
||||
|
||||
void des3_decrypt_pubkey_ossh(unsigned char *key, unsigned char *iv,
|
||||
unsigned char *blk, int len)
|
||||
void des3_decrypt_pubkey_ossh(const void *vkey, const void *viv,
|
||||
void *vblk, int len)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
const unsigned char *iv = (const unsigned char *)viv;
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
DESContext ourkeys[3];
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]);
|
||||
@@ -890,9 +900,12 @@ void des3_decrypt_pubkey_ossh(unsigned char *key, unsigned char *iv,
|
||||
smemclr(ourkeys, sizeof(ourkeys));
|
||||
}
|
||||
|
||||
void des3_encrypt_pubkey_ossh(unsigned char *key, unsigned char *iv,
|
||||
unsigned char *blk, int len)
|
||||
void des3_encrypt_pubkey_ossh(const void *vkey, const void *viv,
|
||||
void *vblk, int len)
|
||||
{
|
||||
const unsigned char *key = (const unsigned char *)vkey;
|
||||
const unsigned char *iv = (const unsigned char *)viv;
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
DESContext ourkeys[3];
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key),
|
||||
GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]);
|
||||
@@ -906,8 +919,9 @@ void des3_encrypt_pubkey_ossh(unsigned char *key, unsigned char *iv,
|
||||
smemclr(ourkeys, sizeof(ourkeys));
|
||||
}
|
||||
|
||||
static void des_keysetup_xdmauth(const unsigned char *keydata, DESContext *dc)
|
||||
static void des_keysetup_xdmauth(const void *vkeydata, DESContext *dc)
|
||||
{
|
||||
const unsigned char *keydata = (const unsigned char *)vkeydata;
|
||||
unsigned char key[8];
|
||||
int i, nbits, j;
|
||||
unsigned int bits;
|
||||
@@ -929,16 +943,14 @@ static void des_keysetup_xdmauth(const unsigned char *keydata, DESContext *dc)
|
||||
des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), dc);
|
||||
}
|
||||
|
||||
void des_encrypt_xdmauth(const unsigned char *keydata,
|
||||
unsigned char *blk, int len)
|
||||
void des_encrypt_xdmauth(const void *keydata, void *blk, int len)
|
||||
{
|
||||
DESContext dc;
|
||||
des_keysetup_xdmauth(keydata, &dc);
|
||||
des_cbc_encrypt(blk, len, &dc);
|
||||
}
|
||||
|
||||
void des_decrypt_xdmauth(const unsigned char *keydata,
|
||||
unsigned char *blk, int len)
|
||||
void des_decrypt_xdmauth(const void *keydata, void *blk, int len)
|
||||
{
|
||||
DESContext dc;
|
||||
des_keysetup_xdmauth(keydata, &dc);
|
||||
@@ -1011,20 +1023,20 @@ const struct ssh_cipher ssh_3des = {
|
||||
8, "triple-DES inner-CBC"
|
||||
};
|
||||
|
||||
static void des_sesskey(void *handle, unsigned char *key)
|
||||
static void des_sesskey(void *handle, const void *key)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_key(keys, key);
|
||||
des_key(keys+1, key);
|
||||
}
|
||||
|
||||
static void des_encrypt_blk(void *handle, unsigned char *blk, int len)
|
||||
static void des_encrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_cbc_encrypt(blk, len, keys);
|
||||
}
|
||||
|
||||
static void des_decrypt_blk(void *handle, unsigned char *blk, int len)
|
||||
static void des_decrypt_blk(void *handle, void *blk, int len)
|
||||
{
|
||||
DESContext *keys = (DESContext *) handle;
|
||||
des_cbc_decrypt(blk, len, keys+1);
|
||||
|
||||
55
source/putty/sshdh.c
vendored
55
source/putty/sshdh.c
vendored
@@ -77,12 +77,18 @@ static const struct dh_extra extra_group14 = {
|
||||
P14, G, lenof(P14), lenof(G),
|
||||
};
|
||||
|
||||
static const struct ssh_kex ssh_diffiehellman_group14_sha256 = {
|
||||
"diffie-hellman-group14-sha256", "group14",
|
||||
KEXTYPE_DH, &ssh_sha256, &extra_group14,
|
||||
};
|
||||
|
||||
static const struct ssh_kex ssh_diffiehellman_group14_sha1 = {
|
||||
"diffie-hellman-group14-sha1", "group14",
|
||||
KEXTYPE_DH, &ssh_sha1, &extra_group14,
|
||||
};
|
||||
|
||||
static const struct ssh_kex *const group14_list[] = {
|
||||
&ssh_diffiehellman_group14_sha256,
|
||||
&ssh_diffiehellman_group14_sha1
|
||||
};
|
||||
|
||||
@@ -115,6 +121,46 @@ const struct ssh_kexes ssh_diffiehellman_gex = {
|
||||
gex_list
|
||||
};
|
||||
|
||||
/*
|
||||
* Suffix on GSSAPI SSH protocol identifiers that indicates Kerberos 5
|
||||
* as the mechanism.
|
||||
*
|
||||
* This suffix is the base64-encoded MD5 hash of the byte sequence
|
||||
* 06 09 2A 86 48 86 F7 12 01 02 02, which in turn is the ASN.1 DER
|
||||
* encoding of the object ID 1.2.840.113554.1.2.2 which designates
|
||||
* Kerberos v5.
|
||||
*
|
||||
* (The same encoded OID, minus the two-byte DER header, is defined in
|
||||
* pgssapi.c as GSS_MECH_KRB5.)
|
||||
*/
|
||||
#define GSS_KRB5_OID_HASH "toWM5Slw5Ew8Mqkay+al2g=="
|
||||
|
||||
static const struct ssh_kex ssh_gssk5_diffiehellman_gex_sha1 = {
|
||||
"gss-gex-sha1-" GSS_KRB5_OID_HASH, NULL,
|
||||
KEXTYPE_GSS, &ssh_sha1, &extra_gex,
|
||||
};
|
||||
|
||||
static const struct ssh_kex ssh_gssk5_diffiehellman_group14_sha1 = {
|
||||
"gss-group14-sha1-" GSS_KRB5_OID_HASH, "group14",
|
||||
KEXTYPE_GSS, &ssh_sha1, &extra_group14,
|
||||
};
|
||||
|
||||
static const struct ssh_kex ssh_gssk5_diffiehellman_group1_sha1 = {
|
||||
"gss-group1-sha1-" GSS_KRB5_OID_HASH, "group1",
|
||||
KEXTYPE_GSS, &ssh_sha1, &extra_group1,
|
||||
};
|
||||
|
||||
static const struct ssh_kex *const gssk5_sha1_kex_list[] = {
|
||||
&ssh_gssk5_diffiehellman_gex_sha1,
|
||||
&ssh_gssk5_diffiehellman_group14_sha1,
|
||||
&ssh_gssk5_diffiehellman_group1_sha1
|
||||
};
|
||||
|
||||
const struct ssh_kexes ssh_gssk5_sha1_kex = {
|
||||
sizeof(gssk5_sha1_kex_list) / sizeof(*gssk5_sha1_kex_list),
|
||||
gssk5_sha1_kex_list
|
||||
};
|
||||
|
||||
/*
|
||||
* Variables.
|
||||
*/
|
||||
@@ -201,7 +247,7 @@ Bignum dh_create_e(void *handle, int nbits)
|
||||
int nbytes;
|
||||
unsigned char *buf;
|
||||
|
||||
nbytes = ssh1_bignum_length(ctx->qmask);
|
||||
nbytes = (bignum_bitcount(ctx->qmask) + 7) / 8;
|
||||
buf = snewn(nbytes, unsigned char);
|
||||
|
||||
do {
|
||||
@@ -212,10 +258,9 @@ Bignum dh_create_e(void *handle, int nbits)
|
||||
if (ctx->x)
|
||||
freebn(ctx->x);
|
||||
if (nbits == 0 || nbits > bignum_bitcount(ctx->qmask)) {
|
||||
ssh1_write_bignum(buf, ctx->qmask);
|
||||
for (i = 2; i < nbytes; i++)
|
||||
buf[i] &= random_byte();
|
||||
ssh1_read_bignum(buf, nbytes, &ctx->x); /* can't fail */
|
||||
for (i = 0; i < nbytes; i++)
|
||||
buf[i] = bignum_byte(ctx->qmask, i) & random_byte();
|
||||
ctx->x = bignum_from_bytes(buf, nbytes);
|
||||
} else {
|
||||
int b, nb;
|
||||
ctx->x = bn_power_2(nbits);
|
||||
|
||||
415
source/putty/sshdss.c
vendored
415
source/putty/sshdss.c
vendored
@@ -9,125 +9,38 @@
|
||||
#include "ssh.h"
|
||||
#include "misc.h"
|
||||
|
||||
static void sha_mpint(SHA_State * s, Bignum b)
|
||||
static void dss_freekey(ssh_key *key); /* forward reference */
|
||||
|
||||
static ssh_key *dss_new_pub(const ssh_keyalg *self, ptrlen data)
|
||||
{
|
||||
unsigned char lenbuf[4];
|
||||
int len;
|
||||
len = (bignum_bitcount(b) + 8) / 8;
|
||||
PUT_32BIT(lenbuf, len);
|
||||
SHA_Bytes(s, lenbuf, 4);
|
||||
while (len-- > 0) {
|
||||
lenbuf[0] = bignum_byte(b, len);
|
||||
SHA_Bytes(s, lenbuf, 1);
|
||||
}
|
||||
smemclr(lenbuf, sizeof(lenbuf));
|
||||
}
|
||||
|
||||
static void sha512_mpint(SHA512_State * s, Bignum b)
|
||||
{
|
||||
unsigned char lenbuf[4];
|
||||
int len;
|
||||
len = (bignum_bitcount(b) + 8) / 8;
|
||||
PUT_32BIT(lenbuf, len);
|
||||
SHA512_Bytes(s, lenbuf, 4);
|
||||
while (len-- > 0) {
|
||||
lenbuf[0] = bignum_byte(b, len);
|
||||
SHA512_Bytes(s, lenbuf, 1);
|
||||
}
|
||||
smemclr(lenbuf, sizeof(lenbuf));
|
||||
}
|
||||
|
||||
static void getstring(const char **data, int *datalen,
|
||||
const char **p, int *length)
|
||||
{
|
||||
*p = NULL;
|
||||
if (*datalen < 4)
|
||||
return;
|
||||
*length = toint(GET_32BIT(*data));
|
||||
if (*length < 0)
|
||||
return;
|
||||
*datalen -= 4;
|
||||
*data += 4;
|
||||
if (*datalen < *length)
|
||||
return;
|
||||
*p = *data;
|
||||
*data += *length;
|
||||
*datalen -= *length;
|
||||
}
|
||||
static Bignum getmp(const char **data, int *datalen)
|
||||
{
|
||||
const char *p;
|
||||
int length;
|
||||
Bignum b;
|
||||
|
||||
getstring(data, datalen, &p, &length);
|
||||
if (!p)
|
||||
return NULL;
|
||||
if (p[0] & 0x80)
|
||||
return NULL; /* negative mp */
|
||||
b = bignum_from_bytes((const unsigned char *)p, length);
|
||||
return b;
|
||||
}
|
||||
|
||||
static Bignum get160(const char **data, int *datalen)
|
||||
{
|
||||
Bignum b;
|
||||
|
||||
if (*datalen < 20)
|
||||
return NULL;
|
||||
|
||||
b = bignum_from_bytes((const unsigned char *)*data, 20);
|
||||
*data += 20;
|
||||
*datalen -= 20;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static void dss_freekey(void *key); /* forward reference */
|
||||
|
||||
static void *dss_newkey(const struct ssh_signkey *self,
|
||||
const char *data, int len)
|
||||
{
|
||||
const char *p;
|
||||
int slen;
|
||||
BinarySource src[1];
|
||||
struct dss_key *dss;
|
||||
|
||||
dss = snew(struct dss_key);
|
||||
getstring(&data, &len, &p, &slen);
|
||||
|
||||
#ifdef DEBUG_DSS
|
||||
{
|
||||
int i;
|
||||
printf("key:");
|
||||
for (i = 0; i < len; i++)
|
||||
printf(" %02x", (unsigned char) (data[i]));
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!p || slen != 7 || memcmp(p, "ssh-dss", 7)) {
|
||||
sfree(dss);
|
||||
BinarySource_BARE_INIT(src, data.ptr, data.len);
|
||||
if (!ptrlen_eq_string(get_string(src), "ssh-dss"))
|
||||
return NULL;
|
||||
}
|
||||
dss->p = getmp(&data, &len);
|
||||
dss->q = getmp(&data, &len);
|
||||
dss->g = getmp(&data, &len);
|
||||
dss->y = getmp(&data, &len);
|
||||
|
||||
dss = snew(struct dss_key);
|
||||
dss->sshk = &ssh_dss;
|
||||
dss->p = get_mp_ssh2(src);
|
||||
dss->q = get_mp_ssh2(src);
|
||||
dss->g = get_mp_ssh2(src);
|
||||
dss->y = get_mp_ssh2(src);
|
||||
dss->x = NULL;
|
||||
|
||||
if (!dss->p || !dss->q || !dss->g || !dss->y ||
|
||||
if (get_err(src) ||
|
||||
!bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) {
|
||||
/* Invalid key. */
|
||||
dss_freekey(dss);
|
||||
dss_freekey(&dss->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dss;
|
||||
return &dss->sshk;
|
||||
}
|
||||
|
||||
static void dss_freekey(void *key)
|
||||
static void dss_freekey(ssh_key *key)
|
||||
{
|
||||
struct dss_key *dss = (struct dss_key *) key;
|
||||
struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk);
|
||||
if (dss->p)
|
||||
freebn(dss->p);
|
||||
if (dss->q)
|
||||
@@ -141,9 +54,9 @@ static void dss_freekey(void *key)
|
||||
sfree(dss);
|
||||
}
|
||||
|
||||
static char *dss_fmtkey(void *key)
|
||||
static char *dss_cache_str(ssh_key *key)
|
||||
{
|
||||
struct dss_key *dss = (struct dss_key *) key;
|
||||
struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk);
|
||||
char *p;
|
||||
int len, i, pos, nibbles;
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
@@ -191,28 +104,19 @@ static char *dss_fmtkey(void *key)
|
||||
return p;
|
||||
}
|
||||
|
||||
static int dss_verifysig(void *key, const char *sig, int siglen,
|
||||
const char *data, int datalen)
|
||||
static int dss_verify(ssh_key *key, ptrlen sig, ptrlen data)
|
||||
{
|
||||
struct dss_key *dss = (struct dss_key *) key;
|
||||
const char *p;
|
||||
int slen;
|
||||
char hash[20];
|
||||
struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk);
|
||||
BinarySource src[1];
|
||||
unsigned char hash[20];
|
||||
Bignum r, s, w, gu1p, yu2p, gu1yu2p, u1, u2, sha, v;
|
||||
int ret;
|
||||
|
||||
if (!dss->p)
|
||||
return 0;
|
||||
|
||||
#ifdef DEBUG_DSS
|
||||
{
|
||||
int i;
|
||||
printf("sig:");
|
||||
for (i = 0; i < siglen; i++)
|
||||
printf(" %02x", (unsigned char) (sig[i]));
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
BinarySource_BARE_INIT(src, sig.ptr, sig.len);
|
||||
|
||||
/*
|
||||
* Commercial SSH (2.0.13) and OpenSSH disagree over the format
|
||||
* of a DSA signature. OpenSSH is in line with RFC 4253:
|
||||
@@ -224,15 +128,18 @@ static int dss_verifysig(void *key, const char *sig, int siglen,
|
||||
* the length: length 40 means the commercial-SSH bug, anything
|
||||
* else is assumed to be RFC-compliant.
|
||||
*/
|
||||
if (siglen != 40) { /* bug not present; read admin fields */
|
||||
getstring(&sig, &siglen, &p, &slen);
|
||||
if (!p || slen != 7 || memcmp(p, "ssh-dss", 7)) {
|
||||
return 0;
|
||||
}
|
||||
sig += 4, siglen -= 4; /* skip yet another length field */
|
||||
if (sig.len != 40) { /* bug not present; read admin fields */
|
||||
ptrlen type = get_string(src);
|
||||
sig = get_string(src);
|
||||
|
||||
if (get_err(src) || !ptrlen_eq_string(type, "ssh-dss") ||
|
||||
sig.len != 40)
|
||||
return 0;
|
||||
}
|
||||
r = get160(&sig, &siglen);
|
||||
s = get160(&sig, &siglen);
|
||||
|
||||
/* Now we're sitting on a 40-byte string for sure. */
|
||||
r = bignum_from_bytes(sig.ptr, 20);
|
||||
s = bignum_from_bytes((const char *)sig.ptr + 20, 20);
|
||||
if (!r || !s) {
|
||||
if (r)
|
||||
freebn(r);
|
||||
@@ -260,10 +167,8 @@ static int dss_verifysig(void *key, const char *sig, int siglen,
|
||||
/*
|
||||
* Step 2. u1 <- SHA(message) * w mod q.
|
||||
*/
|
||||
SHA_Simple(data, datalen, (unsigned char *)hash);
|
||||
p = hash;
|
||||
slen = 20;
|
||||
sha = get160(&p, &slen);
|
||||
SHA_Simple(data.ptr, data.len, hash);
|
||||
sha = bignum_from_bytes(hash, 20);
|
||||
u1 = modmul(sha, w, dss->q);
|
||||
|
||||
/*
|
||||
@@ -299,108 +204,58 @@ static int dss_verifysig(void *key, const char *sig, int siglen,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned char *dss_public_blob(void *key, int *len)
|
||||
static void dss_public_blob(ssh_key *key, BinarySink *bs)
|
||||
{
|
||||
struct dss_key *dss = (struct dss_key *) key;
|
||||
int plen, qlen, glen, ylen, bloblen;
|
||||
int i;
|
||||
unsigned char *blob, *p;
|
||||
struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk);
|
||||
|
||||
plen = (bignum_bitcount(dss->p) + 8) / 8;
|
||||
qlen = (bignum_bitcount(dss->q) + 8) / 8;
|
||||
glen = (bignum_bitcount(dss->g) + 8) / 8;
|
||||
ylen = (bignum_bitcount(dss->y) + 8) / 8;
|
||||
|
||||
/*
|
||||
* string "ssh-dss", mpint p, mpint q, mpint g, mpint y. Total
|
||||
* 27 + sum of lengths. (five length fields, 20+7=27).
|
||||
*/
|
||||
bloblen = 27 + plen + qlen + glen + ylen;
|
||||
blob = snewn(bloblen, unsigned char);
|
||||
p = blob;
|
||||
PUT_32BIT(p, 7);
|
||||
p += 4;
|
||||
memcpy(p, "ssh-dss", 7);
|
||||
p += 7;
|
||||
PUT_32BIT(p, plen);
|
||||
p += 4;
|
||||
for (i = plen; i--;)
|
||||
*p++ = bignum_byte(dss->p, i);
|
||||
PUT_32BIT(p, qlen);
|
||||
p += 4;
|
||||
for (i = qlen; i--;)
|
||||
*p++ = bignum_byte(dss->q, i);
|
||||
PUT_32BIT(p, glen);
|
||||
p += 4;
|
||||
for (i = glen; i--;)
|
||||
*p++ = bignum_byte(dss->g, i);
|
||||
PUT_32BIT(p, ylen);
|
||||
p += 4;
|
||||
for (i = ylen; i--;)
|
||||
*p++ = bignum_byte(dss->y, i);
|
||||
assert(p == blob + bloblen);
|
||||
*len = bloblen;
|
||||
return blob;
|
||||
put_stringz(bs, "ssh-dss");
|
||||
put_mp_ssh2(bs, dss->p);
|
||||
put_mp_ssh2(bs, dss->q);
|
||||
put_mp_ssh2(bs, dss->g);
|
||||
put_mp_ssh2(bs, dss->y);
|
||||
}
|
||||
|
||||
static unsigned char *dss_private_blob(void *key, int *len)
|
||||
static void dss_private_blob(ssh_key *key, BinarySink *bs)
|
||||
{
|
||||
struct dss_key *dss = (struct dss_key *) key;
|
||||
int xlen, bloblen;
|
||||
int i;
|
||||
unsigned char *blob, *p;
|
||||
struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk);
|
||||
|
||||
xlen = (bignum_bitcount(dss->x) + 8) / 8;
|
||||
|
||||
/*
|
||||
* mpint x, string[20] the SHA of p||q||g. Total 4 + xlen.
|
||||
*/
|
||||
bloblen = 4 + xlen;
|
||||
blob = snewn(bloblen, unsigned char);
|
||||
p = blob;
|
||||
PUT_32BIT(p, xlen);
|
||||
p += 4;
|
||||
for (i = xlen; i--;)
|
||||
*p++ = bignum_byte(dss->x, i);
|
||||
assert(p == blob + bloblen);
|
||||
*len = bloblen;
|
||||
return blob;
|
||||
put_mp_ssh2(bs, dss->x);
|
||||
}
|
||||
|
||||
static void *dss_createkey(const struct ssh_signkey *self,
|
||||
const unsigned char *pub_blob, int pub_len,
|
||||
const unsigned char *priv_blob, int priv_len)
|
||||
static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv)
|
||||
{
|
||||
BinarySource src[1];
|
||||
ssh_key *sshk;
|
||||
struct dss_key *dss;
|
||||
const char *pb = (const char *) priv_blob;
|
||||
const char *hash;
|
||||
int hashlen;
|
||||
ptrlen hash;
|
||||
SHA_State s;
|
||||
unsigned char digest[20];
|
||||
Bignum ytest;
|
||||
|
||||
dss = dss_newkey(self, (char *) pub_blob, pub_len);
|
||||
if (!dss)
|
||||
sshk = dss_new_pub(self, pub);
|
||||
if (!sshk)
|
||||
return NULL;
|
||||
dss->x = getmp(&pb, &priv_len);
|
||||
if (!dss->x) {
|
||||
dss_freekey(dss);
|
||||
|
||||
dss = FROMFIELD(sshk, struct dss_key, sshk);
|
||||
BinarySource_BARE_INIT(src, priv.ptr, priv.len);
|
||||
dss->x = get_mp_ssh2(src);
|
||||
if (get_err(src)) {
|
||||
dss_freekey(&dss->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the obsolete hash in the old DSS key format.
|
||||
*/
|
||||
hashlen = -1;
|
||||
getstring(&pb, &priv_len, &hash, &hashlen);
|
||||
if (hashlen == 20) {
|
||||
hash = get_string(src);
|
||||
if (hash.len == 20) {
|
||||
SHA_Init(&s);
|
||||
sha_mpint(&s, dss->p);
|
||||
sha_mpint(&s, dss->q);
|
||||
sha_mpint(&s, dss->g);
|
||||
put_mp_ssh2(&s, dss->p);
|
||||
put_mp_ssh2(&s, dss->q);
|
||||
put_mp_ssh2(&s, dss->g);
|
||||
SHA_Final(&s, digest);
|
||||
if (0 != memcmp(hash, digest, 20)) {
|
||||
dss_freekey(dss);
|
||||
if (0 != memcmp(hash.ptr, digest, 20)) {
|
||||
dss_freekey(&dss->sshk);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -410,78 +265,63 @@ static void *dss_createkey(const struct ssh_signkey *self,
|
||||
*/
|
||||
ytest = modpow(dss->g, dss->x, dss->p);
|
||||
if (0 != bignum_cmp(ytest, dss->y)) {
|
||||
dss_freekey(dss);
|
||||
dss_freekey(&dss->sshk);
|
||||
freebn(ytest);
|
||||
return NULL;
|
||||
}
|
||||
freebn(ytest);
|
||||
|
||||
return dss;
|
||||
return &dss->sshk;
|
||||
}
|
||||
|
||||
static void *dss_openssh_createkey(const struct ssh_signkey *self,
|
||||
const unsigned char **blob, int *len)
|
||||
static ssh_key *dss_new_priv_openssh(const ssh_keyalg *self,
|
||||
BinarySource *src)
|
||||
{
|
||||
const char **b = (const char **) blob;
|
||||
struct dss_key *dss;
|
||||
|
||||
dss = snew(struct dss_key);
|
||||
dss->sshk = &ssh_dss;
|
||||
|
||||
dss->p = getmp(b, len);
|
||||
dss->q = getmp(b, len);
|
||||
dss->g = getmp(b, len);
|
||||
dss->y = getmp(b, len);
|
||||
dss->x = getmp(b, len);
|
||||
dss->p = get_mp_ssh2(src);
|
||||
dss->q = get_mp_ssh2(src);
|
||||
dss->g = get_mp_ssh2(src);
|
||||
dss->y = get_mp_ssh2(src);
|
||||
dss->x = get_mp_ssh2(src);
|
||||
|
||||
if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x ||
|
||||
if (get_err(src) ||
|
||||
!bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) {
|
||||
/* Invalid key. */
|
||||
dss_freekey(dss);
|
||||
dss_freekey(&dss->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dss;
|
||||
return &dss->sshk;
|
||||
}
|
||||
|
||||
static int dss_openssh_fmtkey(void *key, unsigned char *blob, int len)
|
||||
static void dss_openssh_blob(ssh_key *key, BinarySink *bs)
|
||||
{
|
||||
struct dss_key *dss = (struct dss_key *) key;
|
||||
int bloblen, i;
|
||||
struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk);
|
||||
|
||||
bloblen =
|
||||
ssh2_bignum_length(dss->p) +
|
||||
ssh2_bignum_length(dss->q) +
|
||||
ssh2_bignum_length(dss->g) +
|
||||
ssh2_bignum_length(dss->y) +
|
||||
ssh2_bignum_length(dss->x);
|
||||
|
||||
if (bloblen > len)
|
||||
return bloblen;
|
||||
|
||||
bloblen = 0;
|
||||
#define ENC(x) \
|
||||
PUT_32BIT(blob+bloblen, ssh2_bignum_length((x))-4); bloblen += 4; \
|
||||
for (i = ssh2_bignum_length((x))-4; i-- ;) blob[bloblen++]=bignum_byte((x),i);
|
||||
ENC(dss->p);
|
||||
ENC(dss->q);
|
||||
ENC(dss->g);
|
||||
ENC(dss->y);
|
||||
ENC(dss->x);
|
||||
|
||||
return bloblen;
|
||||
put_mp_ssh2(bs, dss->p);
|
||||
put_mp_ssh2(bs, dss->q);
|
||||
put_mp_ssh2(bs, dss->g);
|
||||
put_mp_ssh2(bs, dss->y);
|
||||
put_mp_ssh2(bs, dss->x);
|
||||
}
|
||||
|
||||
static int dss_pubkey_bits(const struct ssh_signkey *self,
|
||||
const void *blob, int len)
|
||||
static int dss_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
|
||||
{
|
||||
ssh_key *sshk;
|
||||
struct dss_key *dss;
|
||||
int ret;
|
||||
|
||||
dss = dss_newkey(self, (const char *) blob, len);
|
||||
if (!dss)
|
||||
sshk = dss_new_pub(self, pub);
|
||||
if (!sshk)
|
||||
return -1;
|
||||
|
||||
dss = FROMFIELD(sshk, struct dss_key, sshk);
|
||||
ret = bignum_bitcount(dss->p);
|
||||
dss_freekey(dss);
|
||||
dss_freekey(&dss->sshk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -568,16 +408,16 @@ Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key,
|
||||
* Hash some identifying text plus x.
|
||||
*/
|
||||
SHA512_Init(&ss);
|
||||
SHA512_Bytes(&ss, id_string, strlen(id_string) + 1);
|
||||
sha512_mpint(&ss, private_key);
|
||||
put_asciz(&ss, id_string);
|
||||
put_mp_ssh2(&ss, private_key);
|
||||
SHA512_Final(&ss, digest512);
|
||||
|
||||
/*
|
||||
* Now hash that digest plus the message hash.
|
||||
*/
|
||||
SHA512_Init(&ss);
|
||||
SHA512_Bytes(&ss, digest512, sizeof(digest512));
|
||||
SHA512_Bytes(&ss, digest, digest_len);
|
||||
put_data(&ss, digest512, sizeof(digest512));
|
||||
put_data(&ss, digest, digest_len);
|
||||
|
||||
while (1) {
|
||||
SHA512_State ss2 = ss; /* structure copy */
|
||||
@@ -601,19 +441,18 @@ Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key,
|
||||
/* Very unlikely we get here, but if so, k was unsuitable. */
|
||||
freebn(k);
|
||||
/* Perturb the hash to think of a different k. */
|
||||
SHA512_Bytes(&ss, "x", 1);
|
||||
put_byte(&ss, 'x');
|
||||
/* Go round and try again. */
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *dss_sign(void *key, const char *data, int datalen,
|
||||
int *siglen)
|
||||
static void dss_sign(ssh_key *key, const void *data, int datalen,
|
||||
BinarySink *bs)
|
||||
{
|
||||
struct dss_key *dss = (struct dss_key *) key;
|
||||
struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk);
|
||||
Bignum k, gkp, hash, kinv, hxr, r, s;
|
||||
unsigned char digest[20];
|
||||
unsigned char *bytes;
|
||||
int nbytes, i;
|
||||
int i;
|
||||
|
||||
SHA_Simple(data, datalen, digest);
|
||||
|
||||
@@ -637,43 +476,31 @@ static unsigned char *dss_sign(void *key, const char *data, int datalen,
|
||||
freebn(k);
|
||||
freebn(hash);
|
||||
|
||||
/*
|
||||
* Signature blob is
|
||||
*
|
||||
* string "ssh-dss"
|
||||
* string two 20-byte numbers r and s, end to end
|
||||
*
|
||||
* i.e. 4+7 + 4+40 bytes.
|
||||
*/
|
||||
nbytes = 4 + 7 + 4 + 40;
|
||||
bytes = snewn(nbytes, unsigned char);
|
||||
PUT_32BIT(bytes, 7);
|
||||
memcpy(bytes + 4, "ssh-dss", 7);
|
||||
PUT_32BIT(bytes + 4 + 7, 40);
|
||||
for (i = 0; i < 20; i++) {
|
||||
bytes[4 + 7 + 4 + i] = bignum_byte(r, 19 - i);
|
||||
bytes[4 + 7 + 4 + 20 + i] = bignum_byte(s, 19 - i);
|
||||
}
|
||||
put_stringz(bs, "ssh-dss");
|
||||
put_uint32(bs, 40);
|
||||
for (i = 0; i < 20; i++)
|
||||
put_byte(bs, bignum_byte(r, 19 - i));
|
||||
for (i = 0; i < 20; i++)
|
||||
put_byte(bs, bignum_byte(s, 19 - i));
|
||||
freebn(r);
|
||||
freebn(s);
|
||||
|
||||
*siglen = nbytes;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const struct ssh_signkey ssh_dss = {
|
||||
dss_newkey,
|
||||
const ssh_keyalg ssh_dss = {
|
||||
dss_new_pub,
|
||||
dss_new_priv,
|
||||
dss_new_priv_openssh,
|
||||
|
||||
dss_freekey,
|
||||
dss_fmtkey,
|
||||
dss_sign,
|
||||
dss_verify,
|
||||
dss_public_blob,
|
||||
dss_private_blob,
|
||||
dss_createkey,
|
||||
dss_openssh_createkey,
|
||||
dss_openssh_fmtkey,
|
||||
5 /* p,q,g,y,x */,
|
||||
dss_openssh_blob,
|
||||
dss_cache_str,
|
||||
|
||||
dss_pubkey_bits,
|
||||
dss_verifysig,
|
||||
dss_sign,
|
||||
|
||||
"ssh-dss",
|
||||
"dss",
|
||||
NULL,
|
||||
|
||||
740
source/putty/sshecc.c
vendored
740
source/putty/sshecc.c
vendored
File diff suppressed because it is too large
Load Diff
23
source/putty/sshgss.h
vendored
23
source/putty/sshgss.h
vendored
@@ -13,6 +13,8 @@ typedef enum Ssh_gss_stat {
|
||||
SSH_GSS_S_CONTINUE_NEEDED,
|
||||
SSH_GSS_NO_MEM,
|
||||
SSH_GSS_BAD_HOST_NAME,
|
||||
SSH_GSS_BAD_MIC,
|
||||
SSH_GSS_NO_CREDS,
|
||||
SSH_GSS_FAILURE
|
||||
} Ssh_gss_stat;
|
||||
|
||||
@@ -26,6 +28,10 @@ typedef enum Ssh_gss_stat {
|
||||
typedef gss_buffer_desc Ssh_gss_buf;
|
||||
typedef gss_name_t Ssh_gss_name;
|
||||
|
||||
#define GSS_NO_EXPIRATION ((time_t)-1)
|
||||
|
||||
#define GSS_DEF_REKEY_MINS 2 /* Default minutes between GSS cache checks */
|
||||
|
||||
/* Functions, provided by either wingss.c or sshgssc.c */
|
||||
|
||||
struct ssh_gss_library;
|
||||
@@ -79,7 +85,8 @@ typedef Ssh_gss_stat (*t_ssh_gss_release_name)(struct ssh_gss_library *lib,
|
||||
typedef Ssh_gss_stat (*t_ssh_gss_init_sec_context)
|
||||
(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx *ctx, Ssh_gss_name name, int delegate,
|
||||
Ssh_gss_buf *in, Ssh_gss_buf *out);
|
||||
Ssh_gss_buf *in, Ssh_gss_buf *out, time_t *expiry,
|
||||
unsigned long *lifetime);
|
||||
|
||||
/*
|
||||
* Frees the contents of an Ssh_gss_buf filled in by
|
||||
@@ -96,7 +103,8 @@ typedef Ssh_gss_stat (*t_ssh_gss_free_tok)(struct ssh_gss_library *lib,
|
||||
* place. Needs to be freed by ssh_gss_release_cred().
|
||||
*/
|
||||
typedef Ssh_gss_stat (*t_ssh_gss_acquire_cred)(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx *);
|
||||
Ssh_gss_ctx *,
|
||||
time_t *expiry);
|
||||
|
||||
/*
|
||||
* Frees the contents of an Ssh_gss_ctx filled in by
|
||||
@@ -111,7 +119,15 @@ typedef Ssh_gss_stat (*t_ssh_gss_release_cred)(struct ssh_gss_library *lib,
|
||||
*/
|
||||
typedef Ssh_gss_stat (*t_ssh_gss_get_mic)(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx ctx, Ssh_gss_buf *in,
|
||||
Ssh_gss_buf *out);
|
||||
Ssh_gss_buf *out);
|
||||
|
||||
/*
|
||||
* Validates an input MIC for some input data.
|
||||
*/
|
||||
typedef Ssh_gss_stat (*t_ssh_gss_verify_mic)(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx ctx,
|
||||
Ssh_gss_buf *in_data,
|
||||
Ssh_gss_buf *in_mic);
|
||||
|
||||
/*
|
||||
* Frees the contents of an Ssh_gss_buf filled in by
|
||||
@@ -161,6 +177,7 @@ struct ssh_gss_library {
|
||||
t_ssh_gss_acquire_cred acquire_cred;
|
||||
t_ssh_gss_release_cred release_cred;
|
||||
t_ssh_gss_get_mic get_mic;
|
||||
t_ssh_gss_verify_mic verify_mic;
|
||||
t_ssh_gss_free_mic free_mic;
|
||||
t_ssh_gss_display_status display_status;
|
||||
|
||||
|
||||
100
source/putty/sshgssc.c
vendored
100
source/putty/sshgssc.c
vendored
@@ -1,6 +1,7 @@
|
||||
#include "putty.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "sshgssc.h"
|
||||
#include "misc.h"
|
||||
|
||||
@@ -38,14 +39,73 @@ static Ssh_gss_stat ssh_gssapi_import_name(struct ssh_gss_library *lib,
|
||||
}
|
||||
|
||||
static Ssh_gss_stat ssh_gssapi_acquire_cred(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx *ctx)
|
||||
Ssh_gss_ctx *ctx,
|
||||
time_t *expiry)
|
||||
{
|
||||
struct gssapi_functions *gss = &lib->u.gssapi;
|
||||
#ifdef MPEXT
|
||||
gss_OID_set_desc k5only;
|
||||
#else
|
||||
gss_OID_set_desc k5only = { 1, GSS_MECH_KRB5 };
|
||||
#endif
|
||||
gss_cred_id_t cred;
|
||||
OM_uint32 dummy;
|
||||
OM_uint32 time_rec;
|
||||
gssapi_ssh_gss_ctx *gssctx = snew(gssapi_ssh_gss_ctx);
|
||||
|
||||
gssctx->maj_stat = gssctx->min_stat = GSS_S_COMPLETE;
|
||||
gssctx->ctx = GSS_C_NO_CONTEXT;
|
||||
*ctx = (Ssh_gss_ctx) gssctx;
|
||||
#ifdef MPEXT
|
||||
k5only.count = 1;
|
||||
k5only.elements = GSS_MECH_KRB5;
|
||||
#endif
|
||||
|
||||
gssctx->ctx = GSS_C_NO_CONTEXT;
|
||||
gssctx->expiry = 0;
|
||||
|
||||
gssctx->maj_stat =
|
||||
gss->acquire_cred(&gssctx->min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE,
|
||||
&k5only, GSS_C_INITIATE, &cred,
|
||||
(gss_OID_set *)0, &time_rec);
|
||||
|
||||
if (gssctx->maj_stat != GSS_S_COMPLETE) {
|
||||
sfree(gssctx);
|
||||
return SSH_GSS_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the credential lifetime is not yet available due to deferred
|
||||
* processing, gss_acquire_cred should return a 0 lifetime which is
|
||||
* distinct from GSS_C_INDEFINITE which signals a crential that never
|
||||
* expires. However, not all implementations get this right, and with
|
||||
* Kerberos, initiator credentials always expire at some point. So when
|
||||
* lifetime is 0 or GSS_C_INDEFINITE we call gss_inquire_cred_by_mech() to
|
||||
* complete deferred processing.
|
||||
*/
|
||||
if (time_rec == GSS_C_INDEFINITE || time_rec == 0) {
|
||||
gssctx->maj_stat =
|
||||
gss->inquire_cred_by_mech(&gssctx->min_stat, cred,
|
||||
(gss_OID) GSS_MECH_KRB5,
|
||||
GSS_C_NO_NAME,
|
||||
&time_rec,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
(void) gss->release_cred(&dummy, &cred);
|
||||
|
||||
if (gssctx->maj_stat != GSS_S_COMPLETE) {
|
||||
sfree(gssctx);
|
||||
return SSH_GSS_FAILURE;
|
||||
}
|
||||
|
||||
if (time_rec != GSS_C_INDEFINITE)
|
||||
gssctx->expiry = time(NULL) + time_rec;
|
||||
else
|
||||
gssctx->expiry = GSS_NO_EXPIRATION;
|
||||
|
||||
if (expiry) {
|
||||
*expiry = gssctx->expiry;
|
||||
}
|
||||
|
||||
*ctx = (Ssh_gss_ctx) gssctx;
|
||||
return SSH_GSS_OK;
|
||||
}
|
||||
|
||||
@@ -54,11 +114,14 @@ static Ssh_gss_stat ssh_gssapi_init_sec_context(struct ssh_gss_library *lib,
|
||||
Ssh_gss_name srv_name,
|
||||
int to_deleg,
|
||||
Ssh_gss_buf *recv_tok,
|
||||
Ssh_gss_buf *send_tok)
|
||||
Ssh_gss_buf *send_tok,
|
||||
time_t *expiry,
|
||||
unsigned long *lifetime)
|
||||
{
|
||||
struct gssapi_functions *gss = &lib->u.gssapi;
|
||||
gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx*) *ctx;
|
||||
OM_uint32 ret_flags;
|
||||
OM_uint32 lifetime_rec;
|
||||
|
||||
if (to_deleg) to_deleg = GSS_C_DELEG_FLAG;
|
||||
gssctx->maj_stat = gss->init_sec_context(&gssctx->min_stat,
|
||||
@@ -74,7 +137,20 @@ static Ssh_gss_stat ssh_gssapi_init_sec_context(struct ssh_gss_library *lib,
|
||||
NULL, /* ignore mech type */
|
||||
send_tok,
|
||||
&ret_flags,
|
||||
NULL); /* ignore time_rec */
|
||||
&lifetime_rec);
|
||||
|
||||
if (lifetime) {
|
||||
if (lifetime_rec == GSS_C_INDEFINITE)
|
||||
*lifetime = ULONG_MAX;
|
||||
else
|
||||
*lifetime = lifetime_rec;
|
||||
}
|
||||
if (expiry) {
|
||||
if (lifetime_rec == GSS_C_INDEFINITE)
|
||||
*expiry = GSS_NO_EXPIRATION;
|
||||
else
|
||||
*expiry = time(NULL) + lifetime_rec;
|
||||
}
|
||||
|
||||
if (gssctx->maj_stat == GSS_S_COMPLETE) return SSH_GSS_S_COMPLETE;
|
||||
if (gssctx->maj_stat == GSS_S_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED;
|
||||
@@ -148,6 +224,7 @@ static Ssh_gss_stat ssh_gssapi_release_cred(struct ssh_gss_library *lib,
|
||||
if (gssctx->ctx != GSS_C_NO_CONTEXT)
|
||||
maj_stat = gss->delete_sec_context(&min_stat,&gssctx->ctx,GSS_C_NO_BUFFER);
|
||||
sfree(gssctx);
|
||||
*ctx = NULL;
|
||||
|
||||
if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK;
|
||||
return SSH_GSS_FAILURE;
|
||||
@@ -175,6 +252,16 @@ static Ssh_gss_stat ssh_gssapi_get_mic(struct ssh_gss_library *lib,
|
||||
return gss->get_mic(&(gssctx->min_stat), gssctx->ctx, 0, buf, hash);
|
||||
}
|
||||
|
||||
static Ssh_gss_stat ssh_gssapi_verify_mic(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
|
||||
Ssh_gss_buf *hash)
|
||||
{
|
||||
struct gssapi_functions *gss = &lib->u.gssapi;
|
||||
gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx;
|
||||
if (gssctx == NULL) return SSH_GSS_FAILURE;
|
||||
return gss->verify_mic(&(gssctx->min_stat), gssctx->ctx, buf, hash, NULL);
|
||||
}
|
||||
|
||||
static Ssh_gss_stat ssh_gssapi_free_mic(struct ssh_gss_library *lib,
|
||||
Ssh_gss_buf *hash)
|
||||
{
|
||||
@@ -192,6 +279,7 @@ void ssh_gssapi_bind_fns(struct ssh_gss_library *lib)
|
||||
lib->acquire_cred = ssh_gssapi_acquire_cred;
|
||||
lib->release_cred = ssh_gssapi_release_cred;
|
||||
lib->get_mic = ssh_gssapi_get_mic;
|
||||
lib->verify_mic = ssh_gssapi_verify_mic;
|
||||
lib->free_mic = ssh_gssapi_free_mic;
|
||||
lib->display_status = ssh_gssapi_display_status;
|
||||
}
|
||||
|
||||
1
source/putty/sshgssc.h
vendored
1
source/putty/sshgssc.h
vendored
@@ -10,6 +10,7 @@ typedef struct gssapi_ssh_gss_ctx {
|
||||
OM_uint32 maj_stat;
|
||||
OM_uint32 min_stat;
|
||||
gss_ctx_id_t ctx;
|
||||
time_t expiry;
|
||||
} gssapi_ssh_gss_ctx;
|
||||
|
||||
void ssh_gssapi_bind_fns(struct ssh_gss_library *lib);
|
||||
|
||||
45
source/putty/sshmd5.c
vendored
45
source/putty/sshmd5.c
vendored
@@ -1,3 +1,4 @@
|
||||
#include <assert.h>
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
@@ -115,20 +116,26 @@ static void MD5_Block(MD5_Core_State * s, uint32 * block)
|
||||
|
||||
#define BLKSIZE 64
|
||||
|
||||
static void MD5_BinarySink_write(BinarySink *bs, const void *data, size_t len);
|
||||
|
||||
void MD5Init(struct MD5Context *s)
|
||||
{
|
||||
MD5_Core_Init(&s->core);
|
||||
s->blkused = 0;
|
||||
s->lenhi = s->lenlo = 0;
|
||||
BinarySink_INIT(s, MD5_BinarySink_write);
|
||||
}
|
||||
|
||||
void MD5Update(struct MD5Context *s, unsigned char const *p, unsigned len)
|
||||
static void MD5_BinarySink_write(BinarySink *bs, const void *data, size_t len)
|
||||
{
|
||||
unsigned char *q = (unsigned char *) p;
|
||||
struct MD5Context *s = BinarySink_DOWNCAST(bs, struct MD5Context);
|
||||
const unsigned char *q = (const unsigned char *)data;
|
||||
uint32 wordblock[16];
|
||||
uint32 lenw = len;
|
||||
int i;
|
||||
|
||||
assert(lenw == len);
|
||||
|
||||
/*
|
||||
* Update the length field.
|
||||
*/
|
||||
@@ -185,7 +192,7 @@ void MD5Final(unsigned char output[16], struct MD5Context *s)
|
||||
|
||||
memset(c, 0, pad);
|
||||
c[0] = 0x80;
|
||||
MD5Update(s, c, pad);
|
||||
put_data(s, c, pad);
|
||||
|
||||
c[7] = (lenhi >> 24) & 0xFF;
|
||||
c[6] = (lenhi >> 16) & 0xFF;
|
||||
@@ -196,7 +203,7 @@ void MD5Final(unsigned char output[16], struct MD5Context *s)
|
||||
c[1] = (lenlo >> 8) & 0xFF;
|
||||
c[0] = (lenlo >> 0) & 0xFF;
|
||||
|
||||
MD5Update(s, c, 8);
|
||||
put_data(s, c, 8);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
output[4 * i + 3] = (s->core.h[i] >> 24) & 0xFF;
|
||||
@@ -211,7 +218,7 @@ void MD5Simple(void const *p, unsigned len, unsigned char output[16])
|
||||
struct MD5Context s;
|
||||
|
||||
MD5Init(&s);
|
||||
MD5Update(&s, (unsigned char const *)p, len);
|
||||
put_data(&s, (unsigned char const *)p, len);
|
||||
MD5Final(output, &s);
|
||||
smemclr(&s, sizeof(s));
|
||||
}
|
||||
@@ -246,18 +253,18 @@ void hmacmd5_key(void *handle, void const *keyv, int len)
|
||||
for (i = 0; i < len && i < 64; i++)
|
||||
foo[i] ^= key[i];
|
||||
MD5Init(&keys[0]);
|
||||
MD5Update(&keys[0], foo, 64);
|
||||
put_data(&keys[0], foo, 64);
|
||||
|
||||
memset(foo, 0x5C, 64);
|
||||
for (i = 0; i < len && i < 64; i++)
|
||||
foo[i] ^= key[i];
|
||||
MD5Init(&keys[1]);
|
||||
MD5Update(&keys[1], foo, 64);
|
||||
put_data(&keys[1], foo, 64);
|
||||
|
||||
smemclr(foo, 64); /* burn the evidence */
|
||||
}
|
||||
|
||||
static void hmacmd5_key_16(void *handle, unsigned char *key)
|
||||
static void hmacmd5_key_16(void *handle, const void *key)
|
||||
{
|
||||
hmacmd5_key(handle, key, 16);
|
||||
}
|
||||
@@ -267,12 +274,13 @@ static void hmacmd5_start(void *handle)
|
||||
struct MD5Context *keys = (struct MD5Context *)handle;
|
||||
|
||||
keys[2] = keys[0]; /* structure copy */
|
||||
BinarySink_COPIED(&keys[2]);
|
||||
}
|
||||
|
||||
static void hmacmd5_bytes(void *handle, unsigned char const *blk, int len)
|
||||
static BinarySink *hmacmd5_sink(void *handle)
|
||||
{
|
||||
struct MD5Context *keys = (struct MD5Context *)handle;
|
||||
MD5Update(&keys[2], blk, len);
|
||||
return BinarySink_UPCAST(&keys[2]);
|
||||
}
|
||||
|
||||
static void hmacmd5_genresult(void *handle, unsigned char *hmac)
|
||||
@@ -282,9 +290,11 @@ static void hmacmd5_genresult(void *handle, unsigned char *hmac)
|
||||
unsigned char intermediate[16];
|
||||
|
||||
s = keys[2]; /* structure copy */
|
||||
BinarySink_COPIED(&s);
|
||||
MD5Final(intermediate, &s);
|
||||
s = keys[1]; /* structure copy */
|
||||
MD5Update(&s, intermediate, 16);
|
||||
BinarySink_COPIED(&s);
|
||||
put_data(&s, intermediate, 16);
|
||||
MD5Final(hmac, &s);
|
||||
}
|
||||
|
||||
@@ -300,9 +310,10 @@ static void hmacmd5_do_hmac_internal(void *handle,
|
||||
unsigned char const *blk2, int len2,
|
||||
unsigned char *hmac)
|
||||
{
|
||||
BinarySink *bs = hmacmd5_sink(handle);
|
||||
hmacmd5_start(handle);
|
||||
hmacmd5_bytes(handle, blk, len);
|
||||
if (blk2) hmacmd5_bytes(handle, blk2, len2);
|
||||
put_data(bs, blk, len);
|
||||
if (blk2) put_data(bs, blk2, len2);
|
||||
hmacmd5_genresult(handle, hmac);
|
||||
}
|
||||
|
||||
@@ -321,15 +332,17 @@ static void hmacmd5_do_hmac_ssh(void *handle, unsigned char const *blk, int len,
|
||||
hmacmd5_do_hmac_internal(handle, seqbuf, 4, blk, len, hmac);
|
||||
}
|
||||
|
||||
static void hmacmd5_generate(void *handle, unsigned char *blk, int len,
|
||||
static void hmacmd5_generate(void *handle, void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
hmacmd5_do_hmac_ssh(handle, blk, len, seq, blk + len);
|
||||
}
|
||||
|
||||
static int hmacmd5_verify(void *handle, unsigned char *blk, int len,
|
||||
static int hmacmd5_verify(void *handle, const void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
const unsigned char *blk = (const unsigned char *)vblk;
|
||||
unsigned char correct[16];
|
||||
hmacmd5_do_hmac_ssh(handle, blk, len, seq, correct);
|
||||
return smemeq(correct, blk + len, 16);
|
||||
@@ -338,7 +351,7 @@ static int hmacmd5_verify(void *handle, unsigned char *blk, int len,
|
||||
const struct ssh_mac ssh_hmac_md5 = {
|
||||
hmacmd5_make_context, hmacmd5_free_context, hmacmd5_key_16,
|
||||
hmacmd5_generate, hmacmd5_verify,
|
||||
hmacmd5_start, hmacmd5_bytes, hmacmd5_genresult, hmacmd5_verresult,
|
||||
hmacmd5_start, hmacmd5_sink, hmacmd5_genresult, hmacmd5_verresult,
|
||||
"hmac-md5", "hmac-md5-etm@openssh.com",
|
||||
16, 16,
|
||||
"HMAC-MD5"
|
||||
|
||||
615
source/putty/sshpubk.c
vendored
615
source/putty/sshpubk.c
vendored
File diff suppressed because it is too large
Load Diff
547
source/putty/sshrsa.c
vendored
547
source/putty/sshrsa.c
vendored
@@ -10,61 +10,39 @@
|
||||
#include "ssh.h"
|
||||
#include "misc.h"
|
||||
|
||||
int makekey(const unsigned char *data, int len, struct RSAKey *result,
|
||||
const unsigned char **keystr, int order)
|
||||
void BinarySource_get_rsa_ssh1_pub(
|
||||
BinarySource *src, struct RSAKey *rsa, RsaSsh1Order order)
|
||||
{
|
||||
const unsigned char *p = data;
|
||||
int i, n;
|
||||
unsigned bits;
|
||||
Bignum e, m;
|
||||
|
||||
if (len < 4)
|
||||
return -1;
|
||||
|
||||
if (result) {
|
||||
result->bits = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
result->bits = (result->bits << 8) + *p++;
|
||||
} else
|
||||
p += 4;
|
||||
|
||||
len -= 4;
|
||||
|
||||
/*
|
||||
* order=0 means exponent then modulus (the keys sent by the
|
||||
* server). order=1 means modulus then exponent (the keys
|
||||
* stored in a keyfile).
|
||||
*/
|
||||
|
||||
if (order == 0) {
|
||||
n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL);
|
||||
if (n < 0) return -1;
|
||||
p += n;
|
||||
len -= n;
|
||||
bits = get_uint32(src);
|
||||
if (order == RSA_SSH1_EXPONENT_FIRST) {
|
||||
e = get_mp_ssh1(src);
|
||||
m = get_mp_ssh1(src);
|
||||
} else {
|
||||
m = get_mp_ssh1(src);
|
||||
e = get_mp_ssh1(src);
|
||||
}
|
||||
|
||||
n = ssh1_read_bignum(p, len, result ? &result->modulus : NULL);
|
||||
if (n < 0 || (result && bignum_bitcount(result->modulus) == 0)) return -1;
|
||||
if (result)
|
||||
result->bytes = n - 2;
|
||||
if (keystr)
|
||||
*keystr = p + 2;
|
||||
p += n;
|
||||
len -= n;
|
||||
|
||||
if (order == 1) {
|
||||
n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL);
|
||||
if (n < 0) return -1;
|
||||
p += n;
|
||||
len -= n;
|
||||
if (rsa) {
|
||||
rsa->bits = bits;
|
||||
rsa->exponent = e;
|
||||
rsa->modulus = m;
|
||||
rsa->bytes = (bignum_bitcount(m) + 7) / 8;
|
||||
} else {
|
||||
freebn(e);
|
||||
freebn(m);
|
||||
}
|
||||
return p - data;
|
||||
}
|
||||
|
||||
int makeprivate(const unsigned char *data, int len, struct RSAKey *result)
|
||||
void BinarySource_get_rsa_ssh1_priv(
|
||||
BinarySource *src, struct RSAKey *rsa)
|
||||
{
|
||||
return ssh1_read_bignum(data, len, &result->private_exponent);
|
||||
rsa->private_exponent = get_mp_ssh1(src);
|
||||
}
|
||||
|
||||
int rsaencrypt(unsigned char *data, int length, struct RSAKey *key)
|
||||
int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key)
|
||||
{
|
||||
Bignum b1, b2;
|
||||
int i;
|
||||
@@ -99,20 +77,6 @@ int rsaencrypt(unsigned char *data, int length, struct RSAKey *key)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sha512_mpint(SHA512_State * s, Bignum b)
|
||||
{
|
||||
unsigned char lenbuf[4];
|
||||
int len;
|
||||
len = (bignum_bitcount(b) + 8) / 8;
|
||||
PUT_32BIT(lenbuf, len);
|
||||
SHA512_Bytes(s, lenbuf, 4);
|
||||
while (len-- > 0) {
|
||||
lenbuf[0] = bignum_byte(b, len);
|
||||
SHA512_Bytes(s, lenbuf, 1);
|
||||
}
|
||||
smemclr(lenbuf, sizeof(lenbuf));
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute (base ^ exp) % mod, provided mod == p * q, with p,q
|
||||
* distinct primes, and iqmp is the multiplicative inverse of q mod p.
|
||||
@@ -237,12 +201,10 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key)
|
||||
* byte = random_byte();
|
||||
*/
|
||||
if (digestused >= lenof(digest512)) {
|
||||
unsigned char seqbuf[4];
|
||||
PUT_32BIT(seqbuf, hashseq);
|
||||
SHA512_Init(&ss);
|
||||
SHA512_Bytes(&ss, "RSA deterministic blinding", 26);
|
||||
SHA512_Bytes(&ss, seqbuf, sizeof(seqbuf));
|
||||
sha512_mpint(&ss, key->private_exponent);
|
||||
put_data(&ss, "RSA deterministic blinding", 26);
|
||||
put_uint32(&ss, hashseq);
|
||||
put_mp_ssh2(&ss, key->private_exponent);
|
||||
SHA512_Final(&ss, digest512);
|
||||
hashseq++;
|
||||
|
||||
@@ -251,8 +213,8 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key)
|
||||
* input.
|
||||
*/
|
||||
SHA512_Init(&ss);
|
||||
SHA512_Bytes(&ss, digest512, sizeof(digest512));
|
||||
sha512_mpint(&ss, input);
|
||||
put_data(&ss, digest512, sizeof(digest512));
|
||||
put_mp_ssh2(&ss, input);
|
||||
SHA512_Final(&ss, digest512);
|
||||
|
||||
digestused = 0;
|
||||
@@ -318,7 +280,7 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bignum rsadecrypt(Bignum input, struct RSAKey *key)
|
||||
Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key)
|
||||
{
|
||||
return rsa_privkey_op(input, key);
|
||||
}
|
||||
@@ -367,38 +329,25 @@ void rsastr_fmt(char *str, struct RSAKey *key)
|
||||
* Generate a fingerprint string for the key. Compatible with the
|
||||
* OpenSSH fingerprint code.
|
||||
*/
|
||||
void rsa_fingerprint(char *str, int len, struct RSAKey *key)
|
||||
char *rsa_ssh1_fingerprint(struct RSAKey *key)
|
||||
{
|
||||
struct MD5Context md5c;
|
||||
unsigned char digest[16];
|
||||
char buffer[16 * 3 + 40];
|
||||
int numlen, slen, i;
|
||||
strbuf *out;
|
||||
int i;
|
||||
|
||||
MD5Init(&md5c);
|
||||
numlen = ssh1_bignum_length(key->modulus) - 2;
|
||||
for (i = numlen; i--;) {
|
||||
unsigned char c = bignum_byte(key->modulus, i);
|
||||
MD5Update(&md5c, &c, 1);
|
||||
}
|
||||
numlen = ssh1_bignum_length(key->exponent) - 2;
|
||||
for (i = numlen; i--;) {
|
||||
unsigned char c = bignum_byte(key->exponent, i);
|
||||
MD5Update(&md5c, &c, 1);
|
||||
}
|
||||
put_mp_ssh1(&md5c, key->modulus);
|
||||
put_mp_ssh1(&md5c, key->exponent);
|
||||
MD5Final(digest, &md5c);
|
||||
|
||||
sprintf(buffer, "%d ", bignum_bitcount(key->modulus));
|
||||
out = strbuf_new();
|
||||
strbuf_catf(out, "%d ", bignum_bitcount(key->modulus));
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(buffer + strlen(buffer), "%s%02x", i ? ":" : "",
|
||||
digest[i]);
|
||||
strncpy(str, buffer, len);
|
||||
str[len - 1] = '\0';
|
||||
slen = strlen(str);
|
||||
if (key->comment && slen < len - 1) {
|
||||
str[slen] = ' ';
|
||||
strncpy(str + slen + 1, key->comment, len - slen - 1);
|
||||
str[len - 1] = '\0';
|
||||
}
|
||||
strbuf_catf(out, "%s%02x", i ? ":" : "", digest[i]);
|
||||
if (key->comment)
|
||||
strbuf_catf(out, " %s", key->comment);
|
||||
return strbuf_to_str(out);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -468,47 +417,37 @@ int rsa_verify(struct RSAKey *key)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Public key blob as used by Pageant: exponent before modulus. */
|
||||
unsigned char *rsa_public_blob(struct RSAKey *key, int *len)
|
||||
void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
|
||||
RsaSsh1Order order)
|
||||
{
|
||||
int length, pos;
|
||||
unsigned char *ret;
|
||||
|
||||
length = (ssh1_bignum_length(key->modulus) +
|
||||
ssh1_bignum_length(key->exponent) + 4);
|
||||
ret = snewn(length, unsigned char);
|
||||
|
||||
PUT_32BIT(ret, bignum_bitcount(key->modulus));
|
||||
pos = 4;
|
||||
pos += ssh1_write_bignum(ret + pos, key->exponent);
|
||||
pos += ssh1_write_bignum(ret + pos, key->modulus);
|
||||
|
||||
*len = length;
|
||||
return ret;
|
||||
put_uint32(bs, bignum_bitcount(key->modulus));
|
||||
if (order == RSA_SSH1_EXPONENT_FIRST) {
|
||||
put_mp_ssh1(bs, key->exponent);
|
||||
put_mp_ssh1(bs, key->modulus);
|
||||
} else {
|
||||
put_mp_ssh1(bs, key->modulus);
|
||||
put_mp_ssh1(bs, key->exponent);
|
||||
}
|
||||
}
|
||||
|
||||
/* Given a public blob, determine its length. */
|
||||
int rsa_public_blob_len(void *data, int maxlen)
|
||||
/* Given an SSH-1 public key blob, determine its length. */
|
||||
int rsa_ssh1_public_blob_len(void *data, int maxlen)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)data;
|
||||
int n;
|
||||
BinarySource src[1];
|
||||
|
||||
if (maxlen < 4)
|
||||
BinarySource_BARE_INIT(src, data, maxlen);
|
||||
|
||||
/* Expect a length word, then exponent and modulus. (It doesn't
|
||||
* even matter which order.) */
|
||||
get_uint32(src);
|
||||
freebn(get_mp_ssh1(src));
|
||||
freebn(get_mp_ssh1(src));
|
||||
|
||||
if (get_err(src))
|
||||
return -1;
|
||||
p += 4; /* length word */
|
||||
maxlen -= 4;
|
||||
|
||||
n = ssh1_read_bignum(p, maxlen, NULL); /* exponent */
|
||||
if (n < 0)
|
||||
return -1;
|
||||
p += n;
|
||||
|
||||
n = ssh1_read_bignum(p, maxlen, NULL); /* modulus */
|
||||
if (n < 0)
|
||||
return -1;
|
||||
p += n;
|
||||
|
||||
return p - (unsigned char *)data;
|
||||
/* Return the number of bytes consumed. */
|
||||
return src->pos;
|
||||
}
|
||||
|
||||
void freersakey(struct RSAKey *key)
|
||||
@@ -533,76 +472,43 @@ void freersakey(struct RSAKey *key)
|
||||
* Implementation of the ssh-rsa signing key type.
|
||||
*/
|
||||
|
||||
static void getstring(const char **data, int *datalen,
|
||||
const char **p, int *length)
|
||||
{
|
||||
*p = NULL;
|
||||
if (*datalen < 4)
|
||||
return;
|
||||
*length = toint(GET_32BIT(*data));
|
||||
if (*length < 0)
|
||||
return;
|
||||
*datalen -= 4;
|
||||
*data += 4;
|
||||
if (*datalen < *length)
|
||||
return;
|
||||
*p = *data;
|
||||
*data += *length;
|
||||
*datalen -= *length;
|
||||
}
|
||||
static Bignum getmp(const char **data, int *datalen)
|
||||
{
|
||||
const char *p;
|
||||
int length;
|
||||
Bignum b;
|
||||
static void rsa2_freekey(ssh_key *key); /* forward reference */
|
||||
|
||||
getstring(data, datalen, &p, &length);
|
||||
if (!p)
|
||||
return NULL;
|
||||
b = bignum_from_bytes((unsigned char *)p, length);
|
||||
return b;
|
||||
}
|
||||
|
||||
static void rsa2_freekey(void *key); /* forward reference */
|
||||
|
||||
static void *rsa2_newkey(const struct ssh_signkey *self,
|
||||
const char *data, int len)
|
||||
static ssh_key *rsa2_new_pub(const ssh_keyalg *self, ptrlen data)
|
||||
{
|
||||
const char *p;
|
||||
int slen;
|
||||
BinarySource src[1];
|
||||
struct RSAKey *rsa;
|
||||
|
||||
rsa = snew(struct RSAKey);
|
||||
getstring(&data, &len, &p, &slen);
|
||||
|
||||
if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) {
|
||||
sfree(rsa);
|
||||
BinarySource_BARE_INIT(src, data.ptr, data.len);
|
||||
if (!ptrlen_eq_string(get_string(src), "ssh-rsa"))
|
||||
return NULL;
|
||||
}
|
||||
rsa->exponent = getmp(&data, &len);
|
||||
rsa->modulus = getmp(&data, &len);
|
||||
|
||||
rsa = snew(struct RSAKey);
|
||||
rsa->sshk = &ssh_rsa;
|
||||
rsa->exponent = get_mp_ssh2(src);
|
||||
rsa->modulus = get_mp_ssh2(src);
|
||||
rsa->private_exponent = NULL;
|
||||
rsa->p = rsa->q = rsa->iqmp = NULL;
|
||||
rsa->comment = NULL;
|
||||
|
||||
if (!rsa->exponent || !rsa->modulus) {
|
||||
rsa2_freekey(rsa);
|
||||
return NULL;
|
||||
if (get_err(src)) {
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rsa;
|
||||
return &rsa->sshk;
|
||||
}
|
||||
|
||||
static void rsa2_freekey(void *key)
|
||||
static void rsa2_freekey(ssh_key *key)
|
||||
{
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
|
||||
freersakey(rsa);
|
||||
sfree(rsa);
|
||||
}
|
||||
|
||||
static char *rsa2_fmtkey(void *key)
|
||||
static char *rsa2_cache_str(ssh_key *key)
|
||||
{
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
|
||||
char *p;
|
||||
int len;
|
||||
|
||||
@@ -612,171 +518,100 @@ static char *rsa2_fmtkey(void *key)
|
||||
return p;
|
||||
}
|
||||
|
||||
static unsigned char *rsa2_public_blob(void *key, int *len)
|
||||
static void rsa2_public_blob(ssh_key *key, BinarySink *bs)
|
||||
{
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
int elen, mlen, bloblen;
|
||||
int i;
|
||||
unsigned char *blob, *p;
|
||||
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
|
||||
|
||||
elen = (bignum_bitcount(rsa->exponent) + 8) / 8;
|
||||
mlen = (bignum_bitcount(rsa->modulus) + 8) / 8;
|
||||
|
||||
/*
|
||||
* string "ssh-rsa", mpint exp, mpint mod. Total 19+elen+mlen.
|
||||
* (three length fields, 12+7=19).
|
||||
*/
|
||||
bloblen = 19 + elen + mlen;
|
||||
blob = snewn(bloblen, unsigned char);
|
||||
p = blob;
|
||||
PUT_32BIT(p, 7);
|
||||
p += 4;
|
||||
memcpy(p, "ssh-rsa", 7);
|
||||
p += 7;
|
||||
PUT_32BIT(p, elen);
|
||||
p += 4;
|
||||
for (i = elen; i--;)
|
||||
*p++ = bignum_byte(rsa->exponent, i);
|
||||
PUT_32BIT(p, mlen);
|
||||
p += 4;
|
||||
for (i = mlen; i--;)
|
||||
*p++ = bignum_byte(rsa->modulus, i);
|
||||
assert(p == blob + bloblen);
|
||||
*len = bloblen;
|
||||
return blob;
|
||||
put_stringz(bs, "ssh-rsa");
|
||||
put_mp_ssh2(bs, rsa->exponent);
|
||||
put_mp_ssh2(bs, rsa->modulus);
|
||||
}
|
||||
|
||||
static unsigned char *rsa2_private_blob(void *key, int *len)
|
||||
static void rsa2_private_blob(ssh_key *key, BinarySink *bs)
|
||||
{
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
int dlen, plen, qlen, ulen, bloblen;
|
||||
int i;
|
||||
unsigned char *blob, *p;
|
||||
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
|
||||
|
||||
dlen = (bignum_bitcount(rsa->private_exponent) + 8) / 8;
|
||||
plen = (bignum_bitcount(rsa->p) + 8) / 8;
|
||||
qlen = (bignum_bitcount(rsa->q) + 8) / 8;
|
||||
ulen = (bignum_bitcount(rsa->iqmp) + 8) / 8;
|
||||
|
||||
/*
|
||||
* mpint private_exp, mpint p, mpint q, mpint iqmp. Total 16 +
|
||||
* sum of lengths.
|
||||
*/
|
||||
bloblen = 16 + dlen + plen + qlen + ulen;
|
||||
blob = snewn(bloblen, unsigned char);
|
||||
p = blob;
|
||||
PUT_32BIT(p, dlen);
|
||||
p += 4;
|
||||
for (i = dlen; i--;)
|
||||
*p++ = bignum_byte(rsa->private_exponent, i);
|
||||
PUT_32BIT(p, plen);
|
||||
p += 4;
|
||||
for (i = plen; i--;)
|
||||
*p++ = bignum_byte(rsa->p, i);
|
||||
PUT_32BIT(p, qlen);
|
||||
p += 4;
|
||||
for (i = qlen; i--;)
|
||||
*p++ = bignum_byte(rsa->q, i);
|
||||
PUT_32BIT(p, ulen);
|
||||
p += 4;
|
||||
for (i = ulen; i--;)
|
||||
*p++ = bignum_byte(rsa->iqmp, i);
|
||||
assert(p == blob + bloblen);
|
||||
*len = bloblen;
|
||||
return blob;
|
||||
put_mp_ssh2(bs, rsa->private_exponent);
|
||||
put_mp_ssh2(bs, rsa->p);
|
||||
put_mp_ssh2(bs, rsa->q);
|
||||
put_mp_ssh2(bs, rsa->iqmp);
|
||||
}
|
||||
|
||||
static void *rsa2_createkey(const struct ssh_signkey *self,
|
||||
const unsigned char *pub_blob, int pub_len,
|
||||
const unsigned char *priv_blob, int priv_len)
|
||||
static ssh_key *rsa2_new_priv(const ssh_keyalg *self,
|
||||
ptrlen pub, ptrlen priv)
|
||||
{
|
||||
BinarySource src[1];
|
||||
ssh_key *sshk;
|
||||
struct RSAKey *rsa;
|
||||
const char *pb = (const char *) priv_blob;
|
||||
|
||||
rsa = rsa2_newkey(self, (char *) pub_blob, pub_len);
|
||||
rsa->private_exponent = getmp(&pb, &priv_len);
|
||||
rsa->p = getmp(&pb, &priv_len);
|
||||
rsa->q = getmp(&pb, &priv_len);
|
||||
rsa->iqmp = getmp(&pb, &priv_len);
|
||||
sshk = rsa2_new_pub(self, pub);
|
||||
if (!sshk)
|
||||
return NULL;
|
||||
|
||||
if (!rsa_verify(rsa)) {
|
||||
rsa2_freekey(rsa);
|
||||
rsa = FROMFIELD(sshk, struct RSAKey, sshk);
|
||||
BinarySource_BARE_INIT(src, priv.ptr, priv.len);
|
||||
rsa->private_exponent = get_mp_ssh2(src);
|
||||
rsa->p = get_mp_ssh2(src);
|
||||
rsa->q = get_mp_ssh2(src);
|
||||
rsa->iqmp = get_mp_ssh2(src);
|
||||
|
||||
if (get_err(src) || !rsa_verify(rsa)) {
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rsa;
|
||||
return &rsa->sshk;
|
||||
}
|
||||
|
||||
static void *rsa2_openssh_createkey(const struct ssh_signkey *self,
|
||||
const unsigned char **blob, int *len)
|
||||
static ssh_key *rsa2_new_priv_openssh(const ssh_keyalg *self,
|
||||
BinarySource *src)
|
||||
{
|
||||
const char **b = (const char **) blob;
|
||||
struct RSAKey *rsa;
|
||||
|
||||
rsa = snew(struct RSAKey);
|
||||
rsa->sshk = &ssh_rsa;
|
||||
rsa->comment = NULL;
|
||||
|
||||
rsa->modulus = getmp(b, len);
|
||||
rsa->exponent = getmp(b, len);
|
||||
rsa->private_exponent = getmp(b, len);
|
||||
rsa->iqmp = getmp(b, len);
|
||||
rsa->p = getmp(b, len);
|
||||
rsa->q = getmp(b, len);
|
||||
rsa->modulus = get_mp_ssh2(src);
|
||||
rsa->exponent = get_mp_ssh2(src);
|
||||
rsa->private_exponent = get_mp_ssh2(src);
|
||||
rsa->iqmp = get_mp_ssh2(src);
|
||||
rsa->p = get_mp_ssh2(src);
|
||||
rsa->q = get_mp_ssh2(src);
|
||||
|
||||
if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent ||
|
||||
!rsa->iqmp || !rsa->p || !rsa->q) {
|
||||
rsa2_freekey(rsa);
|
||||
if (get_err(src) || !rsa_verify(rsa)) {
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!rsa_verify(rsa)) {
|
||||
rsa2_freekey(rsa);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rsa;
|
||||
return &rsa->sshk;
|
||||
}
|
||||
|
||||
static int rsa2_openssh_fmtkey(void *key, unsigned char *blob, int len)
|
||||
static void rsa2_openssh_blob(ssh_key *key, BinarySink *bs)
|
||||
{
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
int bloblen, i;
|
||||
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
|
||||
|
||||
bloblen =
|
||||
ssh2_bignum_length(rsa->modulus) +
|
||||
ssh2_bignum_length(rsa->exponent) +
|
||||
ssh2_bignum_length(rsa->private_exponent) +
|
||||
ssh2_bignum_length(rsa->iqmp) +
|
||||
ssh2_bignum_length(rsa->p) + ssh2_bignum_length(rsa->q);
|
||||
|
||||
if (bloblen > len)
|
||||
return bloblen;
|
||||
|
||||
bloblen = 0;
|
||||
#define ENC(x) \
|
||||
PUT_32BIT(blob+bloblen, ssh2_bignum_length((x))-4); bloblen += 4; \
|
||||
for (i = ssh2_bignum_length((x))-4; i-- ;) blob[bloblen++]=bignum_byte((x),i);
|
||||
ENC(rsa->modulus);
|
||||
ENC(rsa->exponent);
|
||||
ENC(rsa->private_exponent);
|
||||
ENC(rsa->iqmp);
|
||||
ENC(rsa->p);
|
||||
ENC(rsa->q);
|
||||
|
||||
return bloblen;
|
||||
put_mp_ssh2(bs, rsa->modulus);
|
||||
put_mp_ssh2(bs, rsa->exponent);
|
||||
put_mp_ssh2(bs, rsa->private_exponent);
|
||||
put_mp_ssh2(bs, rsa->iqmp);
|
||||
put_mp_ssh2(bs, rsa->p);
|
||||
put_mp_ssh2(bs, rsa->q);
|
||||
}
|
||||
|
||||
static int rsa2_pubkey_bits(const struct ssh_signkey *self,
|
||||
const void *blob, int len)
|
||||
static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
|
||||
{
|
||||
ssh_key *sshk;
|
||||
struct RSAKey *rsa;
|
||||
int ret;
|
||||
|
||||
rsa = rsa2_newkey(self, (const char *) blob, len);
|
||||
if (!rsa)
|
||||
return -1;
|
||||
sshk = rsa2_new_pub(self, pub);
|
||||
if (!sshk)
|
||||
return -1;
|
||||
|
||||
rsa = FROMFIELD(sshk, struct RSAKey, sshk);
|
||||
ret = bignum_bitcount(rsa->modulus);
|
||||
rsa2_freekey(rsa);
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -812,23 +647,32 @@ static const unsigned char asn1_weird_stuff[] = {
|
||||
|
||||
#define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) )
|
||||
|
||||
static int rsa2_verifysig(void *key, const char *sig, int siglen,
|
||||
const char *data, int datalen)
|
||||
static int rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
|
||||
{
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
|
||||
BinarySource src[1];
|
||||
ptrlen type, in_pl;
|
||||
Bignum in, out;
|
||||
const char *p;
|
||||
int slen;
|
||||
int bytes, i, j, ret;
|
||||
unsigned char hash[20];
|
||||
|
||||
getstring(&sig, &siglen, &p, &slen);
|
||||
if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) {
|
||||
BinarySource_BARE_INIT(src, sig.ptr, sig.len);
|
||||
type = get_string(src);
|
||||
/*
|
||||
* RFC 4253 section 6.6: the signature integer in an ssh-rsa
|
||||
* signature is 'without lengths or padding'. That is, we _don't_
|
||||
* expect the usual leading zero byte if the topmost bit of the
|
||||
* first byte is set. (However, because of the possibility of
|
||||
* BUG_SSH2_RSA_PADDING at the other end, we tolerate it if it's
|
||||
* there.) So we can't use get_mp_ssh2, which enforces that
|
||||
* leading-byte scheme; instead we use get_string and
|
||||
* bignum_from_bytes, which will tolerate anything.
|
||||
*/
|
||||
in_pl = get_string(src);
|
||||
if (get_err(src) || !ptrlen_eq_string(type, "ssh-rsa"))
|
||||
return 0;
|
||||
}
|
||||
in = getmp(&sig, &siglen);
|
||||
if (!in)
|
||||
return 0;
|
||||
|
||||
in = bignum_from_bytes(in_pl.ptr, in_pl.len);
|
||||
out = modpow(in, rsa->exponent, rsa->modulus);
|
||||
freebn(in);
|
||||
|
||||
@@ -852,7 +696,7 @@ static int rsa2_verifysig(void *key, const char *sig, int siglen,
|
||||
ret = 0;
|
||||
}
|
||||
/* Finally, we expect to see the SHA-1 hash of the signed data. */
|
||||
SHA_Simple(data, datalen, hash);
|
||||
SHA_Simple(data.ptr, data.len, hash);
|
||||
for (i = 19, j = 0; i >= 0; i--, j++) {
|
||||
if (bignum_byte(out, i) != hash[j])
|
||||
ret = 0;
|
||||
@@ -862,10 +706,10 @@ static int rsa2_verifysig(void *key, const char *sig, int siglen,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned char *rsa2_sign(void *key, const char *data, int datalen,
|
||||
int *siglen)
|
||||
static void rsa2_sign(ssh_key *key, const void *data, int datalen,
|
||||
BinarySink *bs)
|
||||
{
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
|
||||
unsigned char *bytes;
|
||||
int nbytes;
|
||||
unsigned char hash[20];
|
||||
@@ -892,51 +736,50 @@ static unsigned char *rsa2_sign(void *key, const char *data, int datalen,
|
||||
out = rsa_privkey_op(in, rsa);
|
||||
freebn(in);
|
||||
|
||||
put_stringz(bs, "ssh-rsa");
|
||||
nbytes = (bignum_bitcount(out) + 7) / 8;
|
||||
bytes = snewn(4 + 7 + 4 + nbytes, unsigned char);
|
||||
PUT_32BIT(bytes, 7);
|
||||
memcpy(bytes + 4, "ssh-rsa", 7);
|
||||
PUT_32BIT(bytes + 4 + 7, nbytes);
|
||||
put_uint32(bs, nbytes);
|
||||
for (i = 0; i < nbytes; i++)
|
||||
bytes[4 + 7 + 4 + i] = bignum_byte(out, nbytes - 1 - i);
|
||||
freebn(out);
|
||||
put_byte(bs, bignum_byte(out, nbytes - 1 - i));
|
||||
|
||||
*siglen = 4 + 7 + 4 + nbytes;
|
||||
return bytes;
|
||||
freebn(out);
|
||||
}
|
||||
|
||||
const struct ssh_signkey ssh_rsa = {
|
||||
rsa2_newkey,
|
||||
const ssh_keyalg ssh_rsa = {
|
||||
rsa2_new_pub,
|
||||
rsa2_new_priv,
|
||||
rsa2_new_priv_openssh,
|
||||
|
||||
rsa2_freekey,
|
||||
rsa2_fmtkey,
|
||||
rsa2_sign,
|
||||
rsa2_verify,
|
||||
rsa2_public_blob,
|
||||
rsa2_private_blob,
|
||||
rsa2_createkey,
|
||||
rsa2_openssh_createkey,
|
||||
rsa2_openssh_fmtkey,
|
||||
6 /* n,e,d,iqmp,q,p */,
|
||||
rsa2_openssh_blob,
|
||||
rsa2_cache_str,
|
||||
|
||||
rsa2_pubkey_bits,
|
||||
rsa2_verifysig,
|
||||
rsa2_sign,
|
||||
|
||||
"ssh-rsa",
|
||||
"rsa2",
|
||||
NULL,
|
||||
};
|
||||
|
||||
void *ssh_rsakex_newkey(char *data, int len)
|
||||
struct RSAKey *ssh_rsakex_newkey(const void *data, int len)
|
||||
{
|
||||
return rsa2_newkey(&ssh_rsa, data, len);
|
||||
ssh_key *sshk = rsa2_new_pub(&ssh_rsa, make_ptrlen(data, len));
|
||||
if (!sshk)
|
||||
return NULL;
|
||||
return FROMFIELD(sshk, struct RSAKey, sshk);
|
||||
}
|
||||
|
||||
void ssh_rsakex_freekey(void *key)
|
||||
void ssh_rsakex_freekey(struct RSAKey *key)
|
||||
{
|
||||
rsa2_freekey(key);
|
||||
rsa2_freekey(&key->sshk);
|
||||
}
|
||||
|
||||
int ssh_rsakex_klen(void *key)
|
||||
int ssh_rsakex_klen(struct RSAKey *rsa)
|
||||
{
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
|
||||
return bignum_bitcount(rsa->modulus);
|
||||
}
|
||||
|
||||
@@ -949,13 +792,14 @@ static void oaep_mask(const struct ssh_hash *h, void *seed, int seedlen,
|
||||
while (datalen > 0) {
|
||||
int i, max = (datalen > h->hlen ? h->hlen : datalen);
|
||||
void *s;
|
||||
unsigned char counter[4], hash[SSH2_KEX_MAX_HASH_LEN];
|
||||
BinarySink *bs;
|
||||
unsigned char hash[SSH2_KEX_MAX_HASH_LEN];
|
||||
|
||||
assert(h->hlen <= SSH2_KEX_MAX_HASH_LEN);
|
||||
PUT_32BIT(counter, count);
|
||||
s = h->init();
|
||||
h->bytes(s, seed, seedlen);
|
||||
h->bytes(s, counter, 4);
|
||||
bs = h->sink(s);
|
||||
put_data(bs, seed, seedlen);
|
||||
put_uint32(bs, count);
|
||||
h->final(s, hash);
|
||||
count++;
|
||||
|
||||
@@ -968,11 +812,9 @@ static void oaep_mask(const struct ssh_hash *h, void *seed, int seedlen,
|
||||
}
|
||||
|
||||
void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen,
|
||||
unsigned char *out, int outlen,
|
||||
void *key)
|
||||
unsigned char *out, int outlen, struct RSAKey *rsa)
|
||||
{
|
||||
Bignum b1, b2;
|
||||
struct RSAKey *rsa = (struct RSAKey *) key;
|
||||
int k, i;
|
||||
char *p;
|
||||
const int HLEN = h->hlen;
|
||||
@@ -1059,15 +901,12 @@ void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen,
|
||||
*/
|
||||
}
|
||||
|
||||
static const struct ssh_rsa_kex_extra ssh_rsa_kex_extra_sha1 = { 1024 };
|
||||
static const struct ssh_rsa_kex_extra ssh_rsa_kex_extra_sha256 = { 2048 };
|
||||
|
||||
static const struct ssh_kex ssh_rsa_kex_sha1 = {
|
||||
"rsa1024-sha1", NULL, KEXTYPE_RSA, &ssh_sha1, &ssh_rsa_kex_extra_sha1,
|
||||
"rsa1024-sha1", NULL, KEXTYPE_RSA, &ssh_sha1, NULL,
|
||||
};
|
||||
|
||||
static const struct ssh_kex ssh_rsa_kex_sha256 = {
|
||||
"rsa2048-sha256", NULL, KEXTYPE_RSA, &ssh_sha256, &ssh_rsa_kex_extra_sha256,
|
||||
"rsa2048-sha256", NULL, KEXTYPE_RSA, &ssh_sha256, NULL,
|
||||
};
|
||||
|
||||
static const struct ssh_kex *const rsa_kex_list[] = {
|
||||
|
||||
345
source/putty/sshsh256.c
vendored
345
source/putty/sshsh256.c
vendored
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "ssh.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Core SHA256 algorithm: processes 16-word blocks into a message digest.
|
||||
@@ -19,7 +20,11 @@
|
||||
#define smallsigma0(x) ( ror((x),7) ^ ror((x),18) ^ shr((x),3) )
|
||||
#define smallsigma1(x) ( ror((x),17) ^ ror((x),19) ^ shr((x),10) )
|
||||
|
||||
static void SHA256_sw(SHA256_State *s, const unsigned char *q, int len);
|
||||
static void SHA256_ni(SHA256_State * s, const unsigned char *q, int len);
|
||||
|
||||
#ifndef WINSCP_VS
|
||||
|
||||
void SHA256_Core_Init(SHA256_State *s) {
|
||||
s->h[0] = 0x6a09e667;
|
||||
s->h[1] = 0xbb67ae85;
|
||||
@@ -100,23 +105,40 @@ void SHA256_Block(SHA256_State *s, uint32 *block) {
|
||||
|
||||
#define BLKSIZE 64
|
||||
|
||||
static void SHA256_BinarySink_write(BinarySink *bs,
|
||||
const void *p, size_t len);
|
||||
|
||||
void SHA256_Init(SHA256_State *s) {
|
||||
SHA256_Core_Init(s);
|
||||
s->blkused = 0;
|
||||
s->lenhi = s->lenlo = 0;
|
||||
if (supports_sha_ni())
|
||||
s->sha256 = &SHA256_ni;
|
||||
else
|
||||
s->sha256 = &SHA256_sw;
|
||||
BinarySink_INIT(s, SHA256_BinarySink_write);
|
||||
}
|
||||
|
||||
void SHA256_Bytes(SHA256_State *s, const void *p, int len) {
|
||||
static void SHA256_BinarySink_write(BinarySink *bs,
|
||||
const void *p, size_t len)
|
||||
{
|
||||
struct SHA256_State *s = BinarySink_DOWNCAST(bs, struct SHA256_State);
|
||||
unsigned char *q = (unsigned char *)p;
|
||||
uint32 wordblock[16];
|
||||
|
||||
uint32 lenw = len;
|
||||
int i;
|
||||
assert(len == lenw);
|
||||
|
||||
/*
|
||||
* Update the length field.
|
||||
*/
|
||||
s->lenlo += lenw;
|
||||
s->lenhi += (s->lenlo < lenw);
|
||||
(*(s->sha256))(s, q, len);
|
||||
}
|
||||
|
||||
static void SHA256_sw(SHA256_State *s, const unsigned char *q, int len) {
|
||||
uint32 wordblock[16];
|
||||
int i;
|
||||
|
||||
if (s->blkused && s->blkused+len < BLKSIZE) {
|
||||
/*
|
||||
@@ -164,18 +186,10 @@ void SHA256_Final(SHA256_State *s, unsigned char *digest) {
|
||||
|
||||
memset(c, 0, pad);
|
||||
c[0] = 0x80;
|
||||
SHA256_Bytes(s, &c, pad);
|
||||
put_data(s, &c, pad);
|
||||
|
||||
c[0] = (lenhi >> 24) & 0xFF;
|
||||
c[1] = (lenhi >> 16) & 0xFF;
|
||||
c[2] = (lenhi >> 8) & 0xFF;
|
||||
c[3] = (lenhi >> 0) & 0xFF;
|
||||
c[4] = (lenlo >> 24) & 0xFF;
|
||||
c[5] = (lenlo >> 16) & 0xFF;
|
||||
c[6] = (lenlo >> 8) & 0xFF;
|
||||
c[7] = (lenlo >> 0) & 0xFF;
|
||||
|
||||
SHA256_Bytes(s, &c, 8);
|
||||
put_uint32(s, lenhi);
|
||||
put_uint32(s, lenlo);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
digest[i*4+0] = (s->h[i] >> 24) & 0xFF;
|
||||
@@ -189,7 +203,7 @@ void SHA256_Simple(const void *p, int len, unsigned char *output) {
|
||||
SHA256_State s;
|
||||
|
||||
SHA256_Init(&s);
|
||||
SHA256_Bytes(&s, p, len);
|
||||
put_data(&s, p, len);
|
||||
SHA256_Final(&s, output);
|
||||
smemclr(&s, sizeof(s));
|
||||
}
|
||||
@@ -214,6 +228,7 @@ static void *sha256_copy(const void *vold)
|
||||
|
||||
s = snew(SHA256_State);
|
||||
*s = *old;
|
||||
BinarySink_COPIED(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -225,11 +240,10 @@ static void sha256_free(void *handle)
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
static void sha256_bytes(void *handle, const void *p, int len)
|
||||
static BinarySink *sha256_sink(void *handle)
|
||||
{
|
||||
SHA256_State *s = handle;
|
||||
|
||||
SHA256_Bytes(s, p, len);
|
||||
return BinarySink_UPCAST(s);
|
||||
}
|
||||
|
||||
static void sha256_final(void *handle, unsigned char *output)
|
||||
@@ -241,7 +255,7 @@ static void sha256_final(void *handle, unsigned char *output)
|
||||
}
|
||||
|
||||
const struct ssh_hash ssh_sha256 = {
|
||||
sha256_init, sha256_copy, sha256_bytes, sha256_final, sha256_free,
|
||||
sha256_init, sha256_copy, sha256_sink, sha256_final, sha256_free,
|
||||
32, "SHA-256"
|
||||
};
|
||||
|
||||
@@ -261,7 +275,8 @@ static void sha256_free_context(void *handle)
|
||||
sfree(handle);
|
||||
}
|
||||
|
||||
static void sha256_key_internal(void *handle, unsigned char *key, int len)
|
||||
static void sha256_key_internal(void *handle,
|
||||
const unsigned char *key, int len)
|
||||
{
|
||||
SHA256_State *keys = (SHA256_State *)handle;
|
||||
unsigned char foo[64];
|
||||
@@ -271,18 +286,18 @@ static void sha256_key_internal(void *handle, unsigned char *key, int len)
|
||||
for (i = 0; i < len && i < 64; i++)
|
||||
foo[i] ^= key[i];
|
||||
SHA256_Init(&keys[0]);
|
||||
SHA256_Bytes(&keys[0], foo, 64);
|
||||
put_data(&keys[0], foo, 64);
|
||||
|
||||
memset(foo, 0x5C, 64);
|
||||
for (i = 0; i < len && i < 64; i++)
|
||||
foo[i] ^= key[i];
|
||||
SHA256_Init(&keys[1]);
|
||||
SHA256_Bytes(&keys[1], foo, 64);
|
||||
put_data(&keys[1], foo, 64);
|
||||
|
||||
smemclr(foo, 64); /* burn the evidence */
|
||||
}
|
||||
|
||||
static void sha256_key(void *handle, unsigned char *key)
|
||||
static void sha256_key(void *handle, const void *key)
|
||||
{
|
||||
sha256_key_internal(handle, key, 32);
|
||||
}
|
||||
@@ -292,12 +307,13 @@ static void hmacsha256_start(void *handle)
|
||||
SHA256_State *keys = (SHA256_State *)handle;
|
||||
|
||||
keys[2] = keys[0]; /* structure copy */
|
||||
BinarySink_COPIED(&keys[2]);
|
||||
}
|
||||
|
||||
static void hmacsha256_bytes(void *handle, unsigned char const *blk, int len)
|
||||
static BinarySink *hmacsha256_sink(void *handle)
|
||||
{
|
||||
SHA256_State *keys = (SHA256_State *)handle;
|
||||
SHA256_Bytes(&keys[2], (void *)blk, len);
|
||||
return BinarySink_UPCAST(&keys[2]);
|
||||
}
|
||||
|
||||
static void hmacsha256_genresult(void *handle, unsigned char *hmac)
|
||||
@@ -307,27 +323,28 @@ static void hmacsha256_genresult(void *handle, unsigned char *hmac)
|
||||
unsigned char intermediate[32];
|
||||
|
||||
s = keys[2]; /* structure copy */
|
||||
BinarySink_COPIED(&s);
|
||||
SHA256_Final(&s, intermediate);
|
||||
s = keys[1]; /* structure copy */
|
||||
SHA256_Bytes(&s, intermediate, 32);
|
||||
BinarySink_COPIED(&s);
|
||||
put_data(&s, intermediate, 32);
|
||||
SHA256_Final(&s, hmac);
|
||||
}
|
||||
|
||||
static void sha256_do_hmac(void *handle, unsigned char *blk, int len,
|
||||
static void sha256_do_hmac(void *handle, const unsigned char *blk, int len,
|
||||
unsigned long seq, unsigned char *hmac)
|
||||
{
|
||||
unsigned char seqbuf[4];
|
||||
|
||||
PUT_32BIT_MSB_FIRST(seqbuf, seq);
|
||||
BinarySink *bs = hmacsha256_sink(handle);
|
||||
hmacsha256_start(handle);
|
||||
hmacsha256_bytes(handle, seqbuf, 4);
|
||||
hmacsha256_bytes(handle, blk, len);
|
||||
put_uint32(bs, seq);
|
||||
put_data(bs, blk, len);
|
||||
hmacsha256_genresult(handle, hmac);
|
||||
}
|
||||
|
||||
static void sha256_generate(void *handle, unsigned char *blk, int len,
|
||||
static void sha256_generate(void *handle, void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
sha256_do_hmac(handle, blk, len, seq, blk + len);
|
||||
}
|
||||
|
||||
@@ -338,9 +355,10 @@ static int hmacsha256_verresult(void *handle, unsigned char const *hmac)
|
||||
return smemeq(correct, hmac, 32);
|
||||
}
|
||||
|
||||
static int sha256_verify(void *handle, unsigned char *blk, int len,
|
||||
static int sha256_verify(void *handle, const void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
const unsigned char *blk = (const unsigned char *)vblk;
|
||||
unsigned char correct[32];
|
||||
sha256_do_hmac(handle, blk, len, seq, correct);
|
||||
return smemeq(correct, blk + len, 32);
|
||||
@@ -349,7 +367,7 @@ static int sha256_verify(void *handle, unsigned char *blk, int len,
|
||||
const struct ssh_mac ssh_hmac_sha256 = {
|
||||
sha256_make_context, sha256_free_context, sha256_key,
|
||||
sha256_generate, sha256_verify,
|
||||
hmacsha256_start, hmacsha256_bytes,
|
||||
hmacsha256_start, hmacsha256_sink,
|
||||
hmacsha256_genresult, hmacsha256_verresult,
|
||||
"hmac-sha2-256", "hmac-sha2-256-etm@openssh.com",
|
||||
32, 32,
|
||||
@@ -406,3 +424,260 @@ int main(void) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef COMPILER_SUPPORTS_SHA_NI
|
||||
|
||||
#if defined _MSC_VER && defined _M_AMD64
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set target architecture for Clang and GCC
|
||||
*/
|
||||
#if !defined(__clang__) && defined(__GNUC__)
|
||||
# pragma GCC target("sha")
|
||||
# pragma GCC target("sse4.1")
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 5))
|
||||
# define FUNC_ISA __attribute__ ((target("sse4.1,sha")))
|
||||
#else
|
||||
# define FUNC_ISA
|
||||
#endif
|
||||
|
||||
#include <wmmintrin.h>
|
||||
#include <smmintrin.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#include <shaintrin.h>
|
||||
#endif
|
||||
|
||||
/* SHA256 implementation using new instructions
|
||||
The code is based on Jeffrey Walton's SHA256 implementation:
|
||||
https://github.com/noloader/SHA-Intrinsics
|
||||
*/
|
||||
FUNC_ISA
|
||||
static void SHA256_ni_(SHA256_State * s, const unsigned char *q, int len) {
|
||||
if (s->blkused && s->blkused+len < BLKSIZE) {
|
||||
/*
|
||||
* Trivial case: just add to the block.
|
||||
*/
|
||||
memcpy(s->block + s->blkused, q, len);
|
||||
s->blkused += len;
|
||||
} else {
|
||||
__m128i STATE0, STATE1;
|
||||
__m128i MSG, TMP;
|
||||
__m128i MSG0, MSG1, MSG2, MSG3;
|
||||
__m128i ABEF_SAVE, CDGH_SAVE;
|
||||
const __m128i MASK = _mm_set_epi64x(0x0c0d0e0f08090a0bULL, 0x0405060700010203ULL);
|
||||
|
||||
/* Load initial values */
|
||||
TMP = _mm_loadu_si128((const __m128i*) &s->h[0]);
|
||||
STATE1 = _mm_loadu_si128((const __m128i*) &s->h[4]);
|
||||
|
||||
TMP = _mm_shuffle_epi32(TMP, 0xB1); /* CDAB */
|
||||
STATE1 = _mm_shuffle_epi32(STATE1, 0x1B); /* EFGH */
|
||||
STATE0 = _mm_alignr_epi8(TMP, STATE1, 8); /* ABEF */
|
||||
STATE1 = _mm_blend_epi16(STATE1, TMP, 0xF0); /* CDGH */
|
||||
/*
|
||||
* We must complete and process at least one block.
|
||||
*/
|
||||
while (s->blkused + len >= BLKSIZE) {
|
||||
memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused);
|
||||
q += BLKSIZE - s->blkused;
|
||||
len -= BLKSIZE - s->blkused;
|
||||
|
||||
/* Save current state */
|
||||
ABEF_SAVE = STATE0;
|
||||
CDGH_SAVE = STATE1;
|
||||
|
||||
/* Rounds 0-3 */
|
||||
MSG = _mm_loadu_si128((const __m128i*) (s->block + 0));
|
||||
MSG0 = _mm_shuffle_epi8(MSG, MASK);
|
||||
MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0xE9B5DBA5B5C0FBCFULL, 0x71374491428A2F98ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
|
||||
/* Rounds 4-7 */
|
||||
MSG1 = _mm_loadu_si128((const __m128i*) (s->block + 16));
|
||||
MSG1 = _mm_shuffle_epi8(MSG1, MASK);
|
||||
MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0xAB1C5ED5923F82A4ULL, 0x59F111F13956C25BULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1);
|
||||
|
||||
/* Rounds 8-11 */
|
||||
MSG2 = _mm_loadu_si128((const __m128i*) (s->block + 32));
|
||||
MSG2 = _mm_shuffle_epi8(MSG2, MASK);
|
||||
MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0x550C7DC3243185BEULL, 0x12835B01D807AA98ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2);
|
||||
|
||||
/* Rounds 12-15 */
|
||||
MSG3 = _mm_loadu_si128((const __m128i*) (s->block + 48));
|
||||
MSG3 = _mm_shuffle_epi8(MSG3, MASK);
|
||||
MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0xC19BF1749BDC06A7ULL, 0x80DEB1FE72BE5D74ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG3, MSG2, 4);
|
||||
MSG0 = _mm_add_epi32(MSG0, TMP);
|
||||
MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3);
|
||||
|
||||
/* Rounds 16-19 */
|
||||
MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x240CA1CC0FC19DC6ULL, 0xEFBE4786E49B69C1ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG0, MSG3, 4);
|
||||
MSG1 = _mm_add_epi32(MSG1, TMP);
|
||||
MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0);
|
||||
|
||||
/* Rounds 20-23 */
|
||||
MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x76F988DA5CB0A9DCULL, 0x4A7484AA2DE92C6FULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG1, MSG0, 4);
|
||||
MSG2 = _mm_add_epi32(MSG2, TMP);
|
||||
MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1);
|
||||
|
||||
/* Rounds 24-27 */
|
||||
MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0xBF597FC7B00327C8ULL, 0xA831C66D983E5152ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG2, MSG1, 4);
|
||||
MSG3 = _mm_add_epi32(MSG3, TMP);
|
||||
MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2);
|
||||
|
||||
/* Rounds 28-31 */
|
||||
MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0x1429296706CA6351ULL, 0xD5A79147C6E00BF3ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG3, MSG2, 4);
|
||||
MSG0 = _mm_add_epi32(MSG0, TMP);
|
||||
MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3);
|
||||
|
||||
/* Rounds 32-35 */
|
||||
MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x53380D134D2C6DFCULL, 0x2E1B213827B70A85ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG0, MSG3, 4);
|
||||
MSG1 = _mm_add_epi32(MSG1, TMP);
|
||||
MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0);
|
||||
|
||||
/* Rounds 36-39 */
|
||||
MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x92722C8581C2C92EULL, 0x766A0ABB650A7354ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG1, MSG0, 4);
|
||||
MSG2 = _mm_add_epi32(MSG2, TMP);
|
||||
MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1);
|
||||
|
||||
/* Rounds 40-43 */
|
||||
MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0xC76C51A3C24B8B70ULL, 0xA81A664BA2BFE8A1ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG2, MSG1, 4);
|
||||
MSG3 = _mm_add_epi32(MSG3, TMP);
|
||||
MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2);
|
||||
|
||||
/* Rounds 44-47 */
|
||||
MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0x106AA070F40E3585ULL, 0xD6990624D192E819ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG3, MSG2, 4);
|
||||
MSG0 = _mm_add_epi32(MSG0, TMP);
|
||||
MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3);
|
||||
|
||||
/* Rounds 48-51 */
|
||||
MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x34B0BCB52748774CULL, 0x1E376C0819A4C116ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG0, MSG3, 4);
|
||||
MSG1 = _mm_add_epi32(MSG1, TMP);
|
||||
MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0);
|
||||
|
||||
/* Rounds 52-55 */
|
||||
MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x682E6FF35B9CCA4FULL, 0x4ED8AA4A391C0CB3ULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG1, MSG0, 4);
|
||||
MSG2 = _mm_add_epi32(MSG2, TMP);
|
||||
MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
|
||||
/* Rounds 56-59 */
|
||||
MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0x8CC7020884C87814ULL, 0x78A5636F748F82EEULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
TMP = _mm_alignr_epi8(MSG2, MSG1, 4);
|
||||
MSG3 = _mm_add_epi32(MSG3, TMP);
|
||||
MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
|
||||
/* Rounds 60-63 */
|
||||
MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0xC67178F2BEF9A3F7ULL, 0xA4506CEB90BEFFFAULL));
|
||||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||||
|
||||
/* Combine state */
|
||||
STATE0 = _mm_add_epi32(STATE0, ABEF_SAVE);
|
||||
STATE1 = _mm_add_epi32(STATE1, CDGH_SAVE);
|
||||
|
||||
s->blkused = 0;
|
||||
}
|
||||
|
||||
TMP = _mm_shuffle_epi32(STATE0, 0x1B); /* FEBA */
|
||||
STATE1 = _mm_shuffle_epi32(STATE1, 0xB1); /* DCHG */
|
||||
STATE0 = _mm_blend_epi16(TMP, STATE1, 0xF0); /* DCBA */
|
||||
STATE1 = _mm_alignr_epi8(STATE1, TMP, 8); /* ABEF */
|
||||
|
||||
/* Save state */
|
||||
_mm_storeu_si128((__m128i*) &s->h[0], STATE0);
|
||||
_mm_storeu_si128((__m128i*) &s->h[4], STATE1);
|
||||
|
||||
memcpy(s->block, q, len);
|
||||
s->blkused = len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround LLVM bug https://bugs.llvm.org/show_bug.cgi?id=34980
|
||||
*/
|
||||
static void SHA256_ni(SHA256_State * s, const unsigned char *q, int len)
|
||||
{
|
||||
SHA256_ni_(s, q, len);
|
||||
}
|
||||
|
||||
#else /* COMPILER_SUPPORTS_AES_NI */
|
||||
|
||||
static void SHA256_ni(SHA256_State * s, const unsigned char *q, int len)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
#endif /* COMPILER_SUPPORTS_AES_NI */
|
||||
|
||||
42
source/putty/sshsh512.c
vendored
42
source/putty/sshsh512.c
vendored
@@ -6,6 +6,7 @@
|
||||
* Modifications made for SHA-384 also
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "ssh.h"
|
||||
|
||||
#define BLKSIZE 128
|
||||
@@ -185,12 +186,16 @@ static void SHA512_Block(SHA512_State *s, uint64 *block) {
|
||||
* at the end, and pass those blocks to the core SHA512 algorithm.
|
||||
*/
|
||||
|
||||
static void SHA512_BinarySink_write(BinarySink *bs,
|
||||
const void *p, size_t len);
|
||||
|
||||
void SHA512_Init(SHA512_State *s) {
|
||||
int i;
|
||||
SHA512_Core_Init(s);
|
||||
s->blkused = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
s->len[i] = 0;
|
||||
BinarySink_INIT(s, SHA512_BinarySink_write);
|
||||
}
|
||||
|
||||
void SHA384_Init(SHA512_State *s) {
|
||||
@@ -199,14 +204,20 @@ void SHA384_Init(SHA512_State *s) {
|
||||
s->blkused = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
s->len[i] = 0;
|
||||
BinarySink_INIT(s, SHA512_BinarySink_write);
|
||||
}
|
||||
|
||||
void SHA512_Bytes(SHA512_State *s, const void *p, int len) {
|
||||
static void SHA512_BinarySink_write(BinarySink *bs,
|
||||
const void *p, size_t len)
|
||||
{
|
||||
SHA512_State *s = BinarySink_DOWNCAST(bs, SHA512_State);
|
||||
unsigned char *q = (unsigned char *)p;
|
||||
uint64 wordblock[16];
|
||||
uint32 lenw = len;
|
||||
int i;
|
||||
|
||||
assert(lenw == len);
|
||||
|
||||
/*
|
||||
* Update the length field.
|
||||
*/
|
||||
@@ -269,16 +280,10 @@ void SHA512_Final(SHA512_State *s, unsigned char *digest) {
|
||||
|
||||
memset(c, 0, pad);
|
||||
c[0] = 0x80;
|
||||
SHA512_Bytes(s, &c, pad);
|
||||
put_data(s, &c, pad);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
c[i*4+0] = (len[3-i] >> 24) & 0xFF;
|
||||
c[i*4+1] = (len[3-i] >> 16) & 0xFF;
|
||||
c[i*4+2] = (len[3-i] >> 8) & 0xFF;
|
||||
c[i*4+3] = (len[3-i] >> 0) & 0xFF;
|
||||
}
|
||||
|
||||
SHA512_Bytes(s, &c, 16);
|
||||
for (i = 0; i < 4; i++)
|
||||
put_uint32(s, len[3-i]);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
uint32 h, l;
|
||||
@@ -304,7 +309,7 @@ void SHA512_Simple(const void *p, int len, unsigned char *output) {
|
||||
SHA512_State s;
|
||||
|
||||
SHA512_Init(&s);
|
||||
SHA512_Bytes(&s, p, len);
|
||||
put_data(&s, p, len);
|
||||
SHA512_Final(&s, output);
|
||||
smemclr(&s, sizeof(s));
|
||||
}
|
||||
@@ -313,7 +318,7 @@ void SHA384_Simple(const void *p, int len, unsigned char *output) {
|
||||
SHA512_State s;
|
||||
|
||||
SHA384_Init(&s);
|
||||
SHA512_Bytes(&s, p, len);
|
||||
put_data(&s, p, len);
|
||||
SHA384_Final(&s, output);
|
||||
smemclr(&s, sizeof(s));
|
||||
}
|
||||
@@ -338,6 +343,7 @@ static void *sha512_copy(const void *vold)
|
||||
|
||||
s = snew(SHA512_State);
|
||||
*s = *old;
|
||||
BinarySink_COPIED(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -349,11 +355,10 @@ static void sha512_free(void *handle)
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
static void sha512_bytes(void *handle, const void *p, int len)
|
||||
static BinarySink *sha512_sink(void *handle)
|
||||
{
|
||||
SHA512_State *s = handle;
|
||||
|
||||
SHA512_Bytes(s, p, len);
|
||||
return BinarySink_UPCAST(s);
|
||||
}
|
||||
|
||||
static void sha512_final(void *handle, unsigned char *output)
|
||||
@@ -365,7 +370,7 @@ static void sha512_final(void *handle, unsigned char *output)
|
||||
}
|
||||
|
||||
const struct ssh_hash ssh_sha512 = {
|
||||
sha512_init, sha512_copy, sha512_bytes, sha512_final, sha512_free,
|
||||
sha512_init, sha512_copy, sha512_sink, sha512_final, sha512_free,
|
||||
64, "SHA-512"
|
||||
};
|
||||
|
||||
@@ -388,7 +393,7 @@ static void sha384_final(void *handle, unsigned char *output)
|
||||
}
|
||||
|
||||
const struct ssh_hash ssh_sha384 = {
|
||||
sha384_init, sha512_copy, sha512_bytes, sha384_final, sha512_free,
|
||||
sha384_init, sha512_copy, sha512_sink, sha384_final, sha512_free,
|
||||
48, "SHA-384"
|
||||
};
|
||||
|
||||
@@ -450,8 +455,7 @@ int main(void) {
|
||||
int n;
|
||||
SHA512_Init(&s);
|
||||
for (n = 0; n < 1000000 / 40; n++)
|
||||
SHA512_Bytes(&s, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
40);
|
||||
put_data(&s, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 40);
|
||||
SHA512_Final(&s, digest);
|
||||
}
|
||||
for (j = 0; j < 64; j++) {
|
||||
|
||||
393
source/putty/sshsha.c
vendored
393
source/putty/sshsha.c
vendored
@@ -7,12 +7,17 @@
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Core SHA algorithm: processes 16-word blocks into a message digest.
|
||||
*/
|
||||
|
||||
#define rol(x,y) ( ((x) << (y)) | (((uint32)x) >> (32-y)) )
|
||||
|
||||
static void sha1_sw(SHA_State * s, const unsigned char *q, int len);
|
||||
static void sha1_ni(SHA_State * s, const unsigned char *q, int len);
|
||||
|
||||
static void SHA_Core_Init(uint32 h[5])
|
||||
{
|
||||
h[0] = 0x67452301;
|
||||
@@ -119,25 +124,39 @@ void SHATransform(word32 * digest, word32 * block)
|
||||
* the end, and pass those blocks to the core SHA algorithm.
|
||||
*/
|
||||
|
||||
static void SHA_BinarySink_write(BinarySink *bs, const void *p, size_t len);
|
||||
|
||||
void SHA_Init(SHA_State * s)
|
||||
{
|
||||
SHA_Core_Init(s->h);
|
||||
s->blkused = 0;
|
||||
s->lenhi = s->lenlo = 0;
|
||||
if (supports_sha_ni())
|
||||
s->sha1 = &sha1_ni;
|
||||
else
|
||||
s->sha1 = &sha1_sw;
|
||||
BinarySink_INIT(s, SHA_BinarySink_write);
|
||||
}
|
||||
|
||||
void SHA_Bytes(SHA_State * s, const void *p, int len)
|
||||
static void SHA_BinarySink_write(BinarySink *bs, const void *p, size_t len)
|
||||
{
|
||||
struct SHA_State *s = BinarySink_DOWNCAST(bs, struct SHA_State);
|
||||
const unsigned char *q = (const unsigned char *) p;
|
||||
uint32 wordblock[16];
|
||||
uint32 lenw = len;
|
||||
int i;
|
||||
assert(lenw == len);
|
||||
|
||||
/*
|
||||
* Update the length field.
|
||||
*/
|
||||
s->lenlo += lenw;
|
||||
s->lenhi += (s->lenlo < lenw);
|
||||
(*(s->sha1))(s, q, len);
|
||||
}
|
||||
|
||||
static void sha1_sw(SHA_State * s, const unsigned char *q, int len)
|
||||
{
|
||||
uint32 wordblock[16];
|
||||
int i;
|
||||
|
||||
if (s->blkused && s->blkused + len < 64) {
|
||||
/*
|
||||
@@ -189,18 +208,10 @@ void SHA_Final(SHA_State * s, unsigned char *output)
|
||||
|
||||
memset(c, 0, pad);
|
||||
c[0] = 0x80;
|
||||
SHA_Bytes(s, &c, pad);
|
||||
put_data(s, &c, pad);
|
||||
|
||||
c[0] = (lenhi >> 24) & 0xFF;
|
||||
c[1] = (lenhi >> 16) & 0xFF;
|
||||
c[2] = (lenhi >> 8) & 0xFF;
|
||||
c[3] = (lenhi >> 0) & 0xFF;
|
||||
c[4] = (lenlo >> 24) & 0xFF;
|
||||
c[5] = (lenlo >> 16) & 0xFF;
|
||||
c[6] = (lenlo >> 8) & 0xFF;
|
||||
c[7] = (lenlo >> 0) & 0xFF;
|
||||
|
||||
SHA_Bytes(s, &c, 8);
|
||||
put_uint32(s, lenhi);
|
||||
put_uint32(s, lenlo);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
output[i * 4] = (s->h[i] >> 24) & 0xFF;
|
||||
@@ -215,7 +226,7 @@ void SHA_Simple(const void *p, int len, unsigned char *output)
|
||||
SHA_State s;
|
||||
|
||||
SHA_Init(&s);
|
||||
SHA_Bytes(&s, p, len);
|
||||
put_data(&s, p, len);
|
||||
SHA_Final(&s, output);
|
||||
smemclr(&s, sizeof(s));
|
||||
}
|
||||
@@ -240,6 +251,7 @@ static void *sha1_copy(const void *vold)
|
||||
|
||||
s = snew(SHA_State);
|
||||
*s = *old;
|
||||
BinarySink_COPIED(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -251,11 +263,10 @@ static void sha1_free(void *handle)
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
static void sha1_bytes(void *handle, const void *p, int len)
|
||||
static BinarySink *sha1_sink(void *handle)
|
||||
{
|
||||
SHA_State *s = handle;
|
||||
|
||||
SHA_Bytes(s, p, len);
|
||||
return BinarySink_UPCAST(s);
|
||||
}
|
||||
|
||||
static void sha1_final(void *handle, unsigned char *output)
|
||||
@@ -267,7 +278,7 @@ static void sha1_final(void *handle, unsigned char *output)
|
||||
}
|
||||
|
||||
const struct ssh_hash ssh_sha1 = {
|
||||
sha1_init, sha1_copy, sha1_bytes, sha1_final, sha1_free, 20, "SHA-1"
|
||||
sha1_init, sha1_copy, sha1_sink, sha1_final, sha1_free, 20, "SHA-1"
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@@ -286,7 +297,7 @@ static void sha1_free_context(void *handle)
|
||||
sfree(handle);
|
||||
}
|
||||
|
||||
static void sha1_key_internal(void *handle, unsigned char *key, int len)
|
||||
static void sha1_key_internal(void *handle, const unsigned char *key, int len)
|
||||
{
|
||||
SHA_State *keys = (SHA_State *)handle;
|
||||
unsigned char foo[64];
|
||||
@@ -296,23 +307,23 @@ static void sha1_key_internal(void *handle, unsigned char *key, int len)
|
||||
for (i = 0; i < len && i < 64; i++)
|
||||
foo[i] ^= key[i];
|
||||
SHA_Init(&keys[0]);
|
||||
SHA_Bytes(&keys[0], foo, 64);
|
||||
put_data(&keys[0], foo, 64);
|
||||
|
||||
memset(foo, 0x5C, 64);
|
||||
for (i = 0; i < len && i < 64; i++)
|
||||
foo[i] ^= key[i];
|
||||
SHA_Init(&keys[1]);
|
||||
SHA_Bytes(&keys[1], foo, 64);
|
||||
put_data(&keys[1], foo, 64);
|
||||
|
||||
smemclr(foo, 64); /* burn the evidence */
|
||||
}
|
||||
|
||||
static void sha1_key(void *handle, unsigned char *key)
|
||||
static void sha1_key(void *handle, const void *key)
|
||||
{
|
||||
sha1_key_internal(handle, key, 20);
|
||||
}
|
||||
|
||||
static void sha1_key_buggy(void *handle, unsigned char *key)
|
||||
static void sha1_key_buggy(void *handle, const void *key)
|
||||
{
|
||||
sha1_key_internal(handle, key, 16);
|
||||
}
|
||||
@@ -322,12 +333,13 @@ static void hmacsha1_start(void *handle)
|
||||
SHA_State *keys = (SHA_State *)handle;
|
||||
|
||||
keys[2] = keys[0]; /* structure copy */
|
||||
BinarySink_COPIED(&keys[2]);
|
||||
}
|
||||
|
||||
static void hmacsha1_bytes(void *handle, unsigned char const *blk, int len)
|
||||
static BinarySink *hmacsha1_sink(void *handle)
|
||||
{
|
||||
SHA_State *keys = (SHA_State *)handle;
|
||||
SHA_Bytes(&keys[2], (void *)blk, len);
|
||||
return BinarySink_UPCAST(&keys[2]);
|
||||
}
|
||||
|
||||
static void hmacsha1_genresult(void *handle, unsigned char *hmac)
|
||||
@@ -337,27 +349,28 @@ static void hmacsha1_genresult(void *handle, unsigned char *hmac)
|
||||
unsigned char intermediate[20];
|
||||
|
||||
s = keys[2]; /* structure copy */
|
||||
BinarySink_COPIED(&s);
|
||||
SHA_Final(&s, intermediate);
|
||||
s = keys[1]; /* structure copy */
|
||||
SHA_Bytes(&s, intermediate, 20);
|
||||
BinarySink_COPIED(&s);
|
||||
put_data(&s, intermediate, 20);
|
||||
SHA_Final(&s, hmac);
|
||||
}
|
||||
|
||||
static void sha1_do_hmac(void *handle, unsigned char *blk, int len,
|
||||
static void sha1_do_hmac(void *handle, const unsigned char *blk, int len,
|
||||
unsigned long seq, unsigned char *hmac)
|
||||
{
|
||||
unsigned char seqbuf[4];
|
||||
|
||||
PUT_32BIT_MSB_FIRST(seqbuf, seq);
|
||||
BinarySink *bs = hmacsha1_sink(handle);
|
||||
hmacsha1_start(handle);
|
||||
hmacsha1_bytes(handle, seqbuf, 4);
|
||||
hmacsha1_bytes(handle, blk, len);
|
||||
put_uint32(bs, seq);
|
||||
put_data(bs, blk, len);
|
||||
hmacsha1_genresult(handle, hmac);
|
||||
}
|
||||
|
||||
static void sha1_generate(void *handle, unsigned char *blk, int len,
|
||||
static void sha1_generate(void *handle, void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
sha1_do_hmac(handle, blk, len, seq, blk + len);
|
||||
}
|
||||
|
||||
@@ -368,9 +381,10 @@ static int hmacsha1_verresult(void *handle, unsigned char const *hmac)
|
||||
return smemeq(correct, hmac, 20);
|
||||
}
|
||||
|
||||
static int sha1_verify(void *handle, unsigned char *blk, int len,
|
||||
static int sha1_verify(void *handle, const void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
const unsigned char *blk = (const unsigned char *)vblk;
|
||||
unsigned char correct[20];
|
||||
sha1_do_hmac(handle, blk, len, seq, correct);
|
||||
return smemeq(correct, blk + len, 20);
|
||||
@@ -383,9 +397,10 @@ static void hmacsha1_96_genresult(void *handle, unsigned char *hmac)
|
||||
memcpy(hmac, full, 12);
|
||||
}
|
||||
|
||||
static void sha1_96_generate(void *handle, unsigned char *blk, int len,
|
||||
static void sha1_96_generate(void *handle, void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
unsigned char *blk = (unsigned char *)vblk;
|
||||
unsigned char full[20];
|
||||
sha1_do_hmac(handle, blk, len, seq, full);
|
||||
memcpy(blk + len, full, 12);
|
||||
@@ -398,9 +413,10 @@ static int hmacsha1_96_verresult(void *handle, unsigned char const *hmac)
|
||||
return smemeq(correct, hmac, 12);
|
||||
}
|
||||
|
||||
static int sha1_96_verify(void *handle, unsigned char *blk, int len,
|
||||
static int sha1_96_verify(void *handle, const void *vblk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
const unsigned char *blk = (const unsigned char *)vblk;
|
||||
unsigned char correct[20];
|
||||
sha1_do_hmac(handle, blk, len, seq, correct);
|
||||
return smemeq(correct, blk + len, 12);
|
||||
@@ -412,17 +428,17 @@ void hmac_sha1_simple(void *key, int keylen, void *data, int datalen,
|
||||
unsigned char intermediate[20];
|
||||
|
||||
sha1_key_internal(states, key, keylen);
|
||||
SHA_Bytes(&states[0], data, datalen);
|
||||
put_data(&states[0], data, datalen);
|
||||
SHA_Final(&states[0], intermediate);
|
||||
|
||||
SHA_Bytes(&states[1], intermediate, 20);
|
||||
put_data(&states[1], intermediate, 20);
|
||||
SHA_Final(&states[1], output);
|
||||
}
|
||||
|
||||
const struct ssh_mac ssh_hmac_sha1 = {
|
||||
sha1_make_context, sha1_free_context, sha1_key,
|
||||
sha1_generate, sha1_verify,
|
||||
hmacsha1_start, hmacsha1_bytes, hmacsha1_genresult, hmacsha1_verresult,
|
||||
hmacsha1_start, hmacsha1_sink, hmacsha1_genresult, hmacsha1_verresult,
|
||||
"hmac-sha1", "hmac-sha1-etm@openssh.com",
|
||||
20, 20,
|
||||
"HMAC-SHA1"
|
||||
@@ -431,7 +447,7 @@ const struct ssh_mac ssh_hmac_sha1 = {
|
||||
const struct ssh_mac ssh_hmac_sha1_96 = {
|
||||
sha1_make_context, sha1_free_context, sha1_key,
|
||||
sha1_96_generate, sha1_96_verify,
|
||||
hmacsha1_start, hmacsha1_bytes,
|
||||
hmacsha1_start, hmacsha1_sink,
|
||||
hmacsha1_96_genresult, hmacsha1_96_verresult,
|
||||
"hmac-sha1-96", "hmac-sha1-96-etm@openssh.com",
|
||||
12, 20,
|
||||
@@ -441,7 +457,7 @@ const struct ssh_mac ssh_hmac_sha1_96 = {
|
||||
const struct ssh_mac ssh_hmac_sha1_buggy = {
|
||||
sha1_make_context, sha1_free_context, sha1_key_buggy,
|
||||
sha1_generate, sha1_verify,
|
||||
hmacsha1_start, hmacsha1_bytes, hmacsha1_genresult, hmacsha1_verresult,
|
||||
hmacsha1_start, hmacsha1_sink, hmacsha1_genresult, hmacsha1_verresult,
|
||||
"hmac-sha1", NULL,
|
||||
20, 16,
|
||||
"bug-compatible HMAC-SHA1"
|
||||
@@ -450,9 +466,300 @@ const struct ssh_mac ssh_hmac_sha1_buggy = {
|
||||
const struct ssh_mac ssh_hmac_sha1_96_buggy = {
|
||||
sha1_make_context, sha1_free_context, sha1_key_buggy,
|
||||
sha1_96_generate, sha1_96_verify,
|
||||
hmacsha1_start, hmacsha1_bytes,
|
||||
hmacsha1_start, hmacsha1_sink,
|
||||
hmacsha1_96_genresult, hmacsha1_96_verresult,
|
||||
"hmac-sha1-96", NULL,
|
||||
12, 16,
|
||||
"bug-compatible HMAC-SHA1-96"
|
||||
};
|
||||
|
||||
#ifdef COMPILER_SUPPORTS_SHA_NI
|
||||
|
||||
#if defined _MSC_VER && defined _M_AMD64
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set target architecture for Clang and GCC
|
||||
*/
|
||||
#if !defined(__clang__) && defined(__GNUC__)
|
||||
# pragma GCC target("sha")
|
||||
# pragma GCC target("sse4.1")
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 5))
|
||||
# define FUNC_ISA __attribute__ ((target("sse4.1,sha")))
|
||||
#else
|
||||
# define FUNC_ISA
|
||||
#endif
|
||||
|
||||
#include <wmmintrin.h>
|
||||
#include <smmintrin.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#include <shaintrin.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Determinators of CPU type
|
||||
*/
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
|
||||
#include <cpuid.h>
|
||||
int supports_sha_ni(void)
|
||||
{
|
||||
unsigned int CPUInfo[4];
|
||||
__cpuid(0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||
if (CPUInfo[0] < 7)
|
||||
return 0;
|
||||
|
||||
__cpuid_count(7, 0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||
return CPUInfo[1] & (1 << 29); /* SHA */
|
||||
}
|
||||
|
||||
#else /* defined(__clang__) || defined(__GNUC__) */
|
||||
|
||||
int supports_sha_ni(void)
|
||||
{
|
||||
unsigned int CPUInfo[4];
|
||||
__cpuid(CPUInfo, 0);
|
||||
if (CPUInfo[0] < 7)
|
||||
return 0;
|
||||
|
||||
__cpuidex(CPUInfo, 7, 0);
|
||||
return CPUInfo[1] & (1 << 29); /* Check SHA */
|
||||
}
|
||||
|
||||
#endif /* defined(__clang__) || defined(__GNUC__) */
|
||||
|
||||
/* SHA1 implementation using new instructions
|
||||
The code is based on Jeffrey Walton's SHA1 implementation:
|
||||
https://github.com/noloader/SHA-Intrinsics
|
||||
*/
|
||||
FUNC_ISA
|
||||
static void sha1_ni_(SHA_State * s, const unsigned char *q, int len)
|
||||
{
|
||||
if (s->blkused && s->blkused + len < 64) {
|
||||
/*
|
||||
* Trivial case: just add to the block.
|
||||
*/
|
||||
memcpy(s->block + s->blkused, q, len);
|
||||
s->blkused += len;
|
||||
} else {
|
||||
__m128i ABCD, ABCD_SAVE, E0, E0_SAVE, E1;
|
||||
const __m128i MASK = _mm_set_epi64x(0x0001020304050607ULL, 0x08090a0b0c0d0e0fULL);
|
||||
|
||||
ABCD = _mm_loadu_si128((const __m128i*) s->h);
|
||||
E0 = _mm_set_epi32(s->h[4], 0, 0, 0);
|
||||
ABCD = _mm_shuffle_epi32(ABCD, 0x1B);
|
||||
|
||||
/*
|
||||
* We must complete and process at least one block.
|
||||
*/
|
||||
while (s->blkused + len >= 64)
|
||||
{
|
||||
__m128i MSG0, MSG1, MSG2, MSG3;
|
||||
memcpy(s->block + s->blkused, q, 64 - s->blkused);
|
||||
q += 64 - s->blkused;
|
||||
len -= 64 - s->blkused;
|
||||
|
||||
/* Save current state */
|
||||
ABCD_SAVE = ABCD;
|
||||
E0_SAVE = E0;
|
||||
|
||||
/* Rounds 0-3 */
|
||||
MSG0 = _mm_loadu_si128((const __m128i*)(s->block + 0));
|
||||
MSG0 = _mm_shuffle_epi8(MSG0, MASK);
|
||||
E0 = _mm_add_epi32(E0, MSG0);
|
||||
E1 = ABCD;
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
||||
|
||||
/* Rounds 4-7 */
|
||||
MSG1 = _mm_loadu_si128((const __m128i*)(s->block + 16));
|
||||
MSG1 = _mm_shuffle_epi8(MSG1, MASK);
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||||
E0 = ABCD;
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0);
|
||||
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
||||
|
||||
/* Rounds 8-11 */
|
||||
MSG2 = _mm_loadu_si128((const __m128i*)(s->block + 32));
|
||||
MSG2 = _mm_shuffle_epi8(MSG2, MASK);
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||||
E1 = ABCD;
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
||||
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
||||
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
||||
|
||||
/* Rounds 12-15 */
|
||||
MSG3 = _mm_loadu_si128((const __m128i*)(s->block + 48));
|
||||
MSG3 = _mm_shuffle_epi8(MSG3, MASK);
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||||
E0 = ABCD;
|
||||
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0);
|
||||
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
||||
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
||||
|
||||
/* Rounds 16-19 */
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
||||
E1 = ABCD;
|
||||
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
||||
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
||||
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
||||
|
||||
/* Rounds 20-23 */
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||||
E0 = ABCD;
|
||||
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
||||
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
||||
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
||||
|
||||
/* Rounds 24-27 */
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||||
E1 = ABCD;
|
||||
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1);
|
||||
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
||||
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
||||
|
||||
/* Rounds 28-31 */
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||||
E0 = ABCD;
|
||||
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
||||
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
||||
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
||||
|
||||
/* Rounds 32-35 */
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
||||
E1 = ABCD;
|
||||
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1);
|
||||
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
||||
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
||||
|
||||
/* Rounds 36-39 */
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||||
E0 = ABCD;
|
||||
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
||||
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
||||
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
||||
|
||||
/* Rounds 40-43 */
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||||
E1 = ABCD;
|
||||
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
||||
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
||||
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
||||
|
||||
/* Rounds 44-47 */
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||||
E0 = ABCD;
|
||||
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2);
|
||||
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
||||
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
||||
|
||||
/* Rounds 48-51 */
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
||||
E1 = ABCD;
|
||||
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
||||
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
||||
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
||||
|
||||
/* Rounds 52-55 */
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||||
E0 = ABCD;
|
||||
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2);
|
||||
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
||||
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
||||
|
||||
/* Rounds 56-59 */
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||||
E1 = ABCD;
|
||||
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
||||
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
||||
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
||||
|
||||
/* Rounds 60-63 */
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||||
E0 = ABCD;
|
||||
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
||||
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
||||
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
||||
|
||||
/* Rounds 64-67 */
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
||||
E1 = ABCD;
|
||||
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3);
|
||||
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
||||
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
||||
|
||||
/* Rounds 68-71 */
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||||
E0 = ABCD;
|
||||
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
||||
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
||||
|
||||
/* Rounds 72-75 */
|
||||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||||
E1 = ABCD;
|
||||
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3);
|
||||
|
||||
/* Rounds 76-79 */
|
||||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||||
E0 = ABCD;
|
||||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
||||
|
||||
/* Combine state */
|
||||
E0 = _mm_sha1nexte_epu32(E0, E0_SAVE);
|
||||
ABCD = _mm_add_epi32(ABCD, ABCD_SAVE);
|
||||
|
||||
s->blkused = 0;
|
||||
}
|
||||
|
||||
ABCD = _mm_shuffle_epi32(ABCD, 0x1B);
|
||||
|
||||
/* Save state */
|
||||
_mm_storeu_si128((__m128i*) s->h, ABCD);
|
||||
s->h[4] = _mm_extract_epi32(E0, 3);
|
||||
|
||||
memcpy(s->block, q, len);
|
||||
s->blkused = len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround LLVM bug https://bugs.llvm.org/show_bug.cgi?id=34980
|
||||
*/
|
||||
static void sha1_ni(SHA_State * s, const unsigned char *q, int len)
|
||||
{
|
||||
sha1_ni_(s, q, len);
|
||||
}
|
||||
|
||||
#else /* COMPILER_SUPPORTS_AES_NI */
|
||||
|
||||
static void sha1_ni(SHA_State * s, const unsigned char *q, int len)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int supports_sha_ni(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* COMPILER_SUPPORTS_AES_NI */
|
||||
|
||||
662
source/putty/sshshare.c
vendored
662
source/putty/sshshare.c
vendored
File diff suppressed because it is too large
Load Diff
214
source/putty/sshzlib.c
vendored
214
source/putty/sshzlib.c
vendored
@@ -41,6 +41,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#ifdef ZLIB_STANDALONE
|
||||
|
||||
/*
|
||||
@@ -57,13 +59,15 @@
|
||||
#define sresize(x, n, type) ( (type *) realloc((x), (n) * sizeof(type)) )
|
||||
#define sfree(x) ( free((x)) )
|
||||
|
||||
#else
|
||||
#include "ssh.h"
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include "ssh.h"
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@@ -370,7 +374,6 @@ struct Outbuf {
|
||||
unsigned long outbits;
|
||||
int noutbits;
|
||||
int firstblock;
|
||||
int comp_disabled;
|
||||
};
|
||||
|
||||
static void outbits(struct Outbuf *out, unsigned long bits, int nbits)
|
||||
@@ -498,14 +501,6 @@ static void zlib_literal(struct LZ77Context *ectx, unsigned char c)
|
||||
{
|
||||
struct Outbuf *out = (struct Outbuf *) ectx->userdata;
|
||||
|
||||
if (out->comp_disabled) {
|
||||
/*
|
||||
* We're in an uncompressed block, so just output the byte.
|
||||
*/
|
||||
outbits(out, c, 8);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c <= 143) {
|
||||
/* 0 through 143 are 8 bits long starting at 00110000. */
|
||||
outbits(out, mirrorbytes[0x30 + c], 8);
|
||||
@@ -521,8 +516,6 @@ static void zlib_match(struct LZ77Context *ectx, int distance, int len)
|
||||
int i, j, k;
|
||||
struct Outbuf *out = (struct Outbuf *) ectx->userdata;
|
||||
|
||||
assert(!out->comp_disabled);
|
||||
|
||||
while (len > 0) {
|
||||
int thislen;
|
||||
|
||||
@@ -619,7 +612,6 @@ void *zlib_compress_init(void)
|
||||
out = snew(struct Outbuf);
|
||||
out->outbits = out->noutbits = 0;
|
||||
out->firstblock = 1;
|
||||
out->comp_disabled = FALSE;
|
||||
ectx->userdata = out;
|
||||
|
||||
return ectx;
|
||||
@@ -633,50 +625,9 @@ void zlib_compress_cleanup(void *handle)
|
||||
sfree(ectx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn off actual LZ77 analysis for one block, to facilitate
|
||||
* construction of a precise-length IGNORE packet. Returns the
|
||||
* length adjustment (which is only valid for packets < 65536
|
||||
* bytes, but that seems reasonable enough).
|
||||
*/
|
||||
static int zlib_disable_compression(void *handle)
|
||||
{
|
||||
struct LZ77Context *ectx = (struct LZ77Context *)handle;
|
||||
struct Outbuf *out = (struct Outbuf *) ectx->userdata;
|
||||
int n;
|
||||
|
||||
out->comp_disabled = TRUE;
|
||||
|
||||
n = 0;
|
||||
/*
|
||||
* If this is the first block, we will start by outputting two
|
||||
* header bytes, and then three bits to begin an uncompressed
|
||||
* block. This will cost three bytes (because we will start on
|
||||
* a byte boundary, this is certain).
|
||||
*/
|
||||
if (out->firstblock) {
|
||||
n = 3;
|
||||
} else {
|
||||
/*
|
||||
* Otherwise, we will output seven bits to close the
|
||||
* previous static block, and _then_ three bits to begin an
|
||||
* uncompressed block, and then flush the current byte.
|
||||
* This may cost two bytes or three, depending on noutbits.
|
||||
*/
|
||||
n += (out->noutbits + 10) / 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we output four bytes for the length / ~length pair in
|
||||
* the uncompressed block.
|
||||
*/
|
||||
n += 4;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int zlib_compress_block(void *handle, unsigned char *block, int len,
|
||||
unsigned char **outblock, int *outlen)
|
||||
void zlib_compress_block(void *handle, unsigned char *block, int len,
|
||||
unsigned char **outblock, int *outlen,
|
||||
int minlen)
|
||||
{
|
||||
struct LZ77Context *ectx = (struct LZ77Context *)handle;
|
||||
struct Outbuf *out = (struct Outbuf *) ectx->userdata;
|
||||
@@ -698,102 +649,60 @@ int zlib_compress_block(void *handle, unsigned char *block, int len,
|
||||
} else
|
||||
in_block = TRUE;
|
||||
|
||||
if (out->comp_disabled) {
|
||||
if (in_block)
|
||||
outbits(out, 0, 7); /* close static block */
|
||||
|
||||
while (len > 0) {
|
||||
int blen = (len < 65535 ? len : 65535);
|
||||
|
||||
/*
|
||||
* Start a Deflate (RFC1951) uncompressed block. We
|
||||
* transmit a zero bit (BFINAL=0), followed by two more
|
||||
* zero bits (BTYPE=00). Of course these are in the
|
||||
* wrong order (00 0), not that it matters.
|
||||
*/
|
||||
outbits(out, 0, 3);
|
||||
|
||||
/*
|
||||
* Output zero bits to align to a byte boundary.
|
||||
*/
|
||||
if (out->noutbits)
|
||||
outbits(out, 0, 8 - out->noutbits);
|
||||
|
||||
/*
|
||||
* Output the block length, and then its one's
|
||||
* complement. They're little-endian, so all we need to
|
||||
* do is pass them straight to outbits() with bit count
|
||||
* 16.
|
||||
*/
|
||||
outbits(out, blen, 16);
|
||||
outbits(out, blen ^ 0xFFFF, 16);
|
||||
|
||||
/*
|
||||
* Do the `compression': we need to pass the data to
|
||||
* lz77_compress so that it will be taken into account
|
||||
* for subsequent (distance,length) pairs. But
|
||||
* lz77_compress is passed FALSE, which means it won't
|
||||
* actually find (or even look for) any matches; so
|
||||
* every character will be passed straight to
|
||||
* zlib_literal which will spot out->comp_disabled and
|
||||
* emit in the uncompressed format.
|
||||
*/
|
||||
lz77_compress(ectx, block, blen, FALSE);
|
||||
|
||||
len -= blen;
|
||||
block += blen;
|
||||
}
|
||||
outbits(out, 2, 3); /* open new block */
|
||||
} else {
|
||||
if (!in_block) {
|
||||
/*
|
||||
* Start a Deflate (RFC1951) fixed-trees block. We
|
||||
* transmit a zero bit (BFINAL=0), followed by a zero
|
||||
* bit and a one bit (BTYPE=01). Of course these are in
|
||||
* the wrong order (01 0).
|
||||
*/
|
||||
outbits(out, 2, 3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the compression.
|
||||
*/
|
||||
lz77_compress(ectx, block, len, TRUE);
|
||||
|
||||
/*
|
||||
* End the block (by transmitting code 256, which is
|
||||
* 0000000 in fixed-tree mode), and transmit some empty
|
||||
* blocks to ensure we have emitted the byte containing the
|
||||
* last piece of genuine data. There are three ways we can
|
||||
* do this:
|
||||
*
|
||||
* - Minimal flush. Output end-of-block and then open a
|
||||
* new static block. This takes 9 bits, which is
|
||||
* guaranteed to flush out the last genuine code in the
|
||||
* closed block; but allegedly zlib can't handle it.
|
||||
*
|
||||
* - Zlib partial flush. Output EOB, open and close an
|
||||
* empty static block, and _then_ open the new block.
|
||||
* This is the best zlib can handle.
|
||||
*
|
||||
* - Zlib sync flush. Output EOB, then an empty
|
||||
* _uncompressed_ block (000, then sync to byte
|
||||
* boundary, then send bytes 00 00 FF FF). Then open the
|
||||
* new block.
|
||||
*
|
||||
* For the moment, we will use Zlib partial flush.
|
||||
*/
|
||||
outbits(out, 0, 7); /* close block */
|
||||
outbits(out, 2, 3 + 7); /* empty static block */
|
||||
outbits(out, 2, 3); /* open new block */
|
||||
if (!in_block) {
|
||||
/*
|
||||
* Start a Deflate (RFC1951) fixed-trees block. We
|
||||
* transmit a zero bit (BFINAL=0), followed by a zero
|
||||
* bit and a one bit (BTYPE=01). Of course these are in
|
||||
* the wrong order (01 0).
|
||||
*/
|
||||
outbits(out, 2, 3);
|
||||
}
|
||||
|
||||
out->comp_disabled = FALSE;
|
||||
/*
|
||||
* Do the compression.
|
||||
*/
|
||||
lz77_compress(ectx, block, len, TRUE);
|
||||
|
||||
/*
|
||||
* End the block (by transmitting code 256, which is
|
||||
* 0000000 in fixed-tree mode), and transmit some empty
|
||||
* blocks to ensure we have emitted the byte containing the
|
||||
* last piece of genuine data. There are three ways we can
|
||||
* do this:
|
||||
*
|
||||
* - Minimal flush. Output end-of-block and then open a
|
||||
* new static block. This takes 9 bits, which is
|
||||
* guaranteed to flush out the last genuine code in the
|
||||
* closed block; but allegedly zlib can't handle it.
|
||||
*
|
||||
* - Zlib partial flush. Output EOB, open and close an
|
||||
* empty static block, and _then_ open the new block.
|
||||
* This is the best zlib can handle.
|
||||
*
|
||||
* - Zlib sync flush. Output EOB, then an empty
|
||||
* _uncompressed_ block (000, then sync to byte
|
||||
* boundary, then send bytes 00 00 FF FF). Then open the
|
||||
* new block.
|
||||
*
|
||||
* For the moment, we will use Zlib partial flush.
|
||||
*/
|
||||
outbits(out, 0, 7); /* close block */
|
||||
outbits(out, 2, 3 + 7); /* empty static block */
|
||||
outbits(out, 2, 3); /* open new block */
|
||||
|
||||
/*
|
||||
* If we've been asked to pad out the compressed data until it's
|
||||
* at least a given length, do so by emitting further empty static
|
||||
* blocks.
|
||||
*/
|
||||
while (out->outlen < minlen) {
|
||||
outbits(out, 0, 7); /* close block */
|
||||
outbits(out, 2, 3); /* open new static block */
|
||||
}
|
||||
|
||||
*outblock = out->outbuf;
|
||||
*outlen = out->outlen;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@@ -1389,7 +1298,6 @@ const struct ssh_compress ssh_zlib = {
|
||||
zlib_decompress_init,
|
||||
zlib_decompress_cleanup,
|
||||
zlib_decompress_block,
|
||||
zlib_disable_compression,
|
||||
"zlib (RFC1950)"
|
||||
};
|
||||
|
||||
|
||||
41
source/putty/version.h
vendored
41
source/putty/version.h
vendored
@@ -1,6 +1,35 @@
|
||||
/* Generated by automated build script */
|
||||
#define RELEASE 0.70
|
||||
#define TEXTVER "Release 0.70+"
|
||||
#define SSHVER "PuTTY-Release-0.70"
|
||||
#define BINARY_VERSION 0,70,0,0
|
||||
#define SOURCE_COMMIT "3cd10509a51edf5a21cdc80aabf7e6a934522d47"
|
||||
/*
|
||||
* This header file provides the various versioning-related #defines
|
||||
* for a particular PuTTY build.
|
||||
*
|
||||
* When my automated build system does a full build, Buildscr
|
||||
* completely overwrites this file with information derived from the
|
||||
* circumstances and type of that build. The information _here_ is
|
||||
* default stuff used for local development runs of 'make'.
|
||||
*/
|
||||
|
||||
#define TEXTVER "Unidentified build"
|
||||
#define SSHVER "PuTTY-Unidentified-Local-Build"
|
||||
#define BINARY_VERSION 0,0,0,0
|
||||
|
||||
#ifndef SOURCE_COMMIT
|
||||
/*
|
||||
* git commit id from which this build was made. This is defined by
|
||||
* Buildscr for official builds - both source archives and prebuilt
|
||||
* binaries - in the course of overwriting this file as described
|
||||
* above. But we put it here under ifdef, so that it can also be
|
||||
* passed in on the command line for Unix local development builds,
|
||||
* which I treat specially because Unix developers - e.g. me - are
|
||||
* quite likely to run 'make install' straight out of their dev
|
||||
* directory so as to use the bleeding-edge code for day-to-day
|
||||
* running.
|
||||
*
|
||||
* Windows doesn't really need the same treatment, because the easiest
|
||||
* way to install a build properly on Windows is to run the installer,
|
||||
* and the easiest way to do that is to run Buildscr, which will
|
||||
* populate this field its own way. It's only the Unix automake build
|
||||
* where you might go straight from local 'make' to 'make install'
|
||||
* without going through Buildscr.
|
||||
*/
|
||||
#define SOURCE_COMMIT "unavailable"
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifndef NO_GSSAPI
|
||||
|
||||
#include <limits.h>
|
||||
#include "putty.h"
|
||||
|
||||
#define SECURITY_WIN32
|
||||
@@ -11,11 +12,33 @@
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
#define UNIX_EPOCH 11644473600ULL /* Seconds from Windows epoch */
|
||||
#define CNS_PERSEC 10000000ULL /* # 100ns per second */
|
||||
|
||||
/*
|
||||
* Note, as a special case, 0 relative to the Windows epoch (unspecified) maps
|
||||
* to 0 relative to the POSIX epoch (unspecified)!
|
||||
*/
|
||||
#define TIME_WIN_TO_POSIX(ft, t) do { \
|
||||
ULARGE_INTEGER uli; \
|
||||
uli.LowPart = (ft).dwLowDateTime; \
|
||||
uli.HighPart = (ft).dwHighDateTime; \
|
||||
if (uli.QuadPart != 0) \
|
||||
uli.QuadPart = uli.QuadPart / CNS_PERSEC - UNIX_EPOCH; \
|
||||
(t) = (time_t) uli.QuadPart; \
|
||||
} while(0)
|
||||
|
||||
/* Windows code to set up the GSSAPI library list. */
|
||||
|
||||
#ifdef _WIN64
|
||||
#define MIT_KERB_SUFFIX "64"
|
||||
#else
|
||||
#define MIT_KERB_SUFFIX "32"
|
||||
#endif
|
||||
|
||||
const int ngsslibs = 3;
|
||||
const char *const gsslibnames[3] = {
|
||||
"MIT Kerberos GSSAPI32.DLL",
|
||||
"MIT Kerberos GSSAPI"MIT_KERB_SUFFIX".DLL",
|
||||
"Microsoft SSPI SECUR32.DLL",
|
||||
"User-specified GSSAPI DLL",
|
||||
};
|
||||
@@ -27,7 +50,7 @@ const struct keyvalwhere gsslibkeywords[] = {
|
||||
|
||||
DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
|
||||
AcquireCredentialsHandleA,
|
||||
(SEC_CHAR *, SEC_CHAR *, ULONG, PLUID,
|
||||
(SEC_CHAR *, SEC_CHAR *, ULONG, PVOID,
|
||||
PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp));
|
||||
DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
|
||||
InitializeSecurityContextA,
|
||||
@@ -49,6 +72,9 @@ DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
|
||||
DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
|
||||
MakeSignature,
|
||||
(PCtxtHandle, ULONG, PSecBufferDesc, ULONG));
|
||||
DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
|
||||
VerifySignature,
|
||||
(PCtxtHandle, PSecBufferDesc, ULONG, PULONG));
|
||||
DECL_WINDOWS_FUNCTION(static, DLL_DIRECTORY_COOKIE,
|
||||
AddDllDirectory,
|
||||
(PCWSTR));
|
||||
@@ -93,7 +119,6 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, void *frontend) // MPEXT
|
||||
list->nlibraries = 0;
|
||||
|
||||
/* MIT Kerberos GSSAPI implementation */
|
||||
/* TODO: For 64-bit builds, check for gssapi64.dll */
|
||||
module = NULL;
|
||||
if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\MIT\\Kerberos", ®key)
|
||||
== ERROR_SUCCESS) {
|
||||
@@ -118,7 +143,7 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, void *frontend) // MPEXT
|
||||
p_AddDllDirectory(dllPath);
|
||||
sfree(dllPath);
|
||||
}
|
||||
strcat (buffer, "\\gssapi32.dll");
|
||||
strcat (buffer, "\\gssapi"MIT_KERB_SUFFIX".dll");
|
||||
module = LoadLibraryEx (buffer, NULL,
|
||||
LOAD_LIBRARY_SEARCH_SYSTEM32 |
|
||||
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
|
||||
@@ -133,7 +158,7 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, void *frontend) // MPEXT
|
||||
&list->libraries[list->nlibraries++];
|
||||
|
||||
lib->id = 0;
|
||||
lib->gsslogmsg = "Using GSSAPI from GSSAPI32.DLL";
|
||||
lib->gsslogmsg = "Using GSSAPI from GSSAPI"MIT_KERB_SUFFIX".DLL";
|
||||
lib->handle = (void *)module;
|
||||
|
||||
#define BIND_GSS_FN(name) \
|
||||
@@ -142,6 +167,7 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, void *frontend) // MPEXT
|
||||
BIND_GSS_FN(delete_sec_context);
|
||||
BIND_GSS_FN(display_status);
|
||||
BIND_GSS_FN(get_mic);
|
||||
BIND_GSS_FN(verify_mic);
|
||||
BIND_GSS_FN(import_name);
|
||||
BIND_GSS_FN(init_sec_context);
|
||||
BIND_GSS_FN(release_buffer);
|
||||
@@ -172,6 +198,7 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, void *frontend) // MPEXT
|
||||
GET_WINDOWS_FUNCTION(module, DeleteSecurityContext);
|
||||
GET_WINDOWS_FUNCTION(module, QueryContextAttributesA);
|
||||
GET_WINDOWS_FUNCTION(module, MakeSignature);
|
||||
GET_WINDOWS_FUNCTION(module, VerifySignature);
|
||||
|
||||
ssh_sspi_bind_fns(lib);
|
||||
}
|
||||
@@ -230,6 +257,7 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, void *frontend) // MPEXT
|
||||
BIND_GSS_FN(delete_sec_context);
|
||||
BIND_GSS_FN(display_status);
|
||||
BIND_GSS_FN(get_mic);
|
||||
BIND_GSS_FN(verify_mic);
|
||||
BIND_GSS_FN(import_name);
|
||||
BIND_GSS_FN(init_sec_context);
|
||||
BIND_GSS_FN(release_buffer);
|
||||
@@ -295,7 +323,8 @@ static Ssh_gss_stat ssh_sspi_import_name(struct ssh_gss_library *lib,
|
||||
}
|
||||
|
||||
static Ssh_gss_stat ssh_sspi_acquire_cred(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx *ctx)
|
||||
Ssh_gss_ctx *ctx,
|
||||
time_t *expiry)
|
||||
{
|
||||
winSsh_gss_ctx *winctx = snew(winSsh_gss_ctx);
|
||||
memset(winctx, 0, sizeof(winSsh_gss_ctx));
|
||||
@@ -315,10 +344,18 @@ static Ssh_gss_stat ssh_sspi_acquire_cred(struct ssh_gss_library *lib,
|
||||
NULL,
|
||||
NULL,
|
||||
&winctx->cred_handle,
|
||||
&winctx->expiry);
|
||||
NULL);
|
||||
|
||||
if (winctx->maj_stat != SEC_E_OK) {
|
||||
p_FreeCredentialsHandle(&winctx->cred_handle);
|
||||
sfree(winctx);
|
||||
return SSH_GSS_FAILURE;
|
||||
}
|
||||
|
||||
/* Windows does not return a valid expiration from AcquireCredentials */
|
||||
if (expiry)
|
||||
*expiry = GSS_NO_EXPIRATION;
|
||||
|
||||
if (winctx->maj_stat != SEC_E_OK) return SSH_GSS_FAILURE;
|
||||
|
||||
*ctx = (Ssh_gss_ctx) winctx;
|
||||
return SSH_GSS_OK;
|
||||
}
|
||||
@@ -355,12 +392,68 @@ static SecBufferDesc ssh_gss_init_sec_buffer_desc(unsigned long version,
|
||||
#define MPEXT_INIT_SEC_BUFFERDESC(VERSION, BUFFERSCOUNT, BUFFERS) \
|
||||
{VERSION, BUFFERSCOUNT, BUFFERS}
|
||||
#endif
|
||||
|
||||
static void localexp_to_exp_lifetime(TimeStamp *localexp,
|
||||
time_t *expiry, unsigned long *lifetime)
|
||||
{
|
||||
FILETIME nowUTC;
|
||||
FILETIME expUTC;
|
||||
time_t now;
|
||||
time_t exp;
|
||||
time_t delta;
|
||||
|
||||
if (!lifetime && !expiry)
|
||||
return;
|
||||
|
||||
GetSystemTimeAsFileTime(&nowUTC);
|
||||
TIME_WIN_TO_POSIX(nowUTC, now);
|
||||
|
||||
if (lifetime)
|
||||
*lifetime = 0;
|
||||
if (expiry)
|
||||
*expiry = GSS_NO_EXPIRATION;
|
||||
|
||||
/*
|
||||
* Type oddity: localexp is a pointer to 'TimeStamp', whereas
|
||||
* LocalFileTimeToFileTime expects a pointer to FILETIME. However,
|
||||
* despite having different formal type names from the compiler's
|
||||
* point of view, these two structures are specified to be
|
||||
* isomorphic in the MS documentation, so it's legitimate to copy
|
||||
* between them:
|
||||
*
|
||||
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380511(v=vs.85).aspx
|
||||
*/
|
||||
{
|
||||
FILETIME localexp_ft;
|
||||
enum { vorpal_sword = 1 / (sizeof(*localexp) == sizeof(localexp_ft)) };
|
||||
memcpy(&localexp_ft, localexp, sizeof(localexp_ft));
|
||||
if (!LocalFileTimeToFileTime(&localexp_ft, &expUTC))
|
||||
return;
|
||||
}
|
||||
|
||||
TIME_WIN_TO_POSIX(expUTC, exp);
|
||||
delta = exp - now;
|
||||
if (exp == 0 || delta <= 0)
|
||||
return;
|
||||
|
||||
if (expiry)
|
||||
*expiry = exp;
|
||||
if (lifetime) {
|
||||
if (delta <= ULONG_MAX)
|
||||
*lifetime = (unsigned long)delta;
|
||||
else
|
||||
*lifetime = ULONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static Ssh_gss_stat ssh_sspi_init_sec_context(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx *ctx,
|
||||
Ssh_gss_name srv_name,
|
||||
int to_deleg,
|
||||
Ssh_gss_buf *recv_tok,
|
||||
Ssh_gss_buf *send_tok)
|
||||
Ssh_gss_buf *send_tok,
|
||||
time_t *expiry,
|
||||
unsigned long *lifetime)
|
||||
{
|
||||
winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) *ctx;
|
||||
SecBuffer wsend_tok = MPEXT_INIT_SEC_BUFFER(send_tok->length,SECBUFFER_TOKEN,send_tok->value);
|
||||
@@ -370,6 +463,7 @@ static Ssh_gss_stat ssh_sspi_init_sec_context(struct ssh_gss_library *lib,
|
||||
unsigned long flags=ISC_REQ_MUTUAL_AUTH|ISC_REQ_REPLAY_DETECT|
|
||||
ISC_REQ_CONFIDENTIALITY|ISC_REQ_ALLOCATE_MEMORY;
|
||||
unsigned long ret_flags=0;
|
||||
TimeStamp localexp;
|
||||
|
||||
/* check if we have to delegate ... */
|
||||
if (to_deleg) flags |= ISC_REQ_DELEGATE;
|
||||
@@ -384,8 +478,10 @@ static Ssh_gss_stat ssh_sspi_init_sec_context(struct ssh_gss_library *lib,
|
||||
&winctx->context,
|
||||
&output_desc,
|
||||
&ret_flags,
|
||||
&winctx->expiry);
|
||||
|
||||
&localexp);
|
||||
|
||||
localexp_to_exp_lifetime(&localexp, expiry, lifetime);
|
||||
|
||||
/* prepare for the next round */
|
||||
winctx->context_handle = &winctx->context;
|
||||
send_tok->value = wsend_tok.pvBuffer;
|
||||
@@ -543,6 +639,36 @@ static Ssh_gss_stat ssh_sspi_get_mic(struct ssh_gss_library *lib,
|
||||
return winctx->maj_stat;
|
||||
}
|
||||
|
||||
static Ssh_gss_stat ssh_sspi_verify_mic(struct ssh_gss_library *lib,
|
||||
Ssh_gss_ctx ctx,
|
||||
Ssh_gss_buf *buf,
|
||||
Ssh_gss_buf *mic)
|
||||
{
|
||||
winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) ctx;
|
||||
SecBufferDesc InputBufferDescriptor;
|
||||
SecBuffer InputSecurityToken[2];
|
||||
ULONG qop;
|
||||
|
||||
if (winctx == NULL) return SSH_GSS_FAILURE;
|
||||
|
||||
winctx->maj_stat = 0;
|
||||
|
||||
InputBufferDescriptor.cBuffers = 2;
|
||||
InputBufferDescriptor.pBuffers = InputSecurityToken;
|
||||
InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
|
||||
InputSecurityToken[0].BufferType = SECBUFFER_DATA;
|
||||
InputSecurityToken[0].cbBuffer = buf->length;
|
||||
InputSecurityToken[0].pvBuffer = buf->value;
|
||||
InputSecurityToken[1].BufferType = SECBUFFER_TOKEN;
|
||||
InputSecurityToken[1].cbBuffer = mic->length;
|
||||
InputSecurityToken[1].pvBuffer = mic->value;
|
||||
|
||||
winctx->maj_stat = p_VerifySignature(&winctx->context,
|
||||
&InputBufferDescriptor,
|
||||
0, &qop);
|
||||
return winctx->maj_stat;
|
||||
}
|
||||
|
||||
static Ssh_gss_stat ssh_sspi_free_mic(struct ssh_gss_library *lib,
|
||||
Ssh_gss_buf *hash)
|
||||
{
|
||||
@@ -560,6 +686,7 @@ static void ssh_sspi_bind_fns(struct ssh_gss_library *lib)
|
||||
lib->acquire_cred = ssh_sspi_acquire_cred;
|
||||
lib->release_cred = ssh_sspi_release_cred;
|
||||
lib->get_mic = ssh_sspi_get_mic;
|
||||
lib->verify_mic = ssh_sspi_verify_mic;
|
||||
lib->free_mic = ssh_sspi_free_mic;
|
||||
lib->display_status = ssh_sspi_display_status;
|
||||
}
|
||||
|
||||
@@ -12,16 +12,11 @@
|
||||
#include "putty.h"
|
||||
#include "network.h"
|
||||
|
||||
typedef struct Socket_handle_tag *Handle_Socket;
|
||||
|
||||
#ifdef MPEXT
|
||||
extern char *do_select(Plug plug, SOCKET skt, int startup);
|
||||
#endif
|
||||
|
||||
struct Socket_handle_tag {
|
||||
const struct socket_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
|
||||
typedef struct HandleSocket {
|
||||
HANDLE send_H, recv_H, stderr_H;
|
||||
struct handle *send_h, *recv_h, *stderr_h;
|
||||
|
||||
@@ -51,29 +46,31 @@ struct Socket_handle_tag {
|
||||
char *error;
|
||||
|
||||
Plug plug;
|
||||
};
|
||||
|
||||
const Socket_vtable *sockvt;
|
||||
} HandleSocket;
|
||||
|
||||
static int handle_gotdata(struct handle *h, void *data, int len)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) handle_get_privdata(h);
|
||||
HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
|
||||
|
||||
if (len < 0) {
|
||||
plug_closing(ps->plug, "Read error from handle", 0, 0);
|
||||
plug_closing(hs->plug, "Read error from handle", 0, 0);
|
||||
return 0;
|
||||
} else if (len == 0) {
|
||||
plug_closing(ps->plug, NULL, 0, 0);
|
||||
plug_closing(hs->plug, NULL, 0, 0);
|
||||
return 0;
|
||||
} else {
|
||||
assert(ps->frozen != FROZEN && ps->frozen != THAWING);
|
||||
if (ps->frozen == FREEZING) {
|
||||
assert(hs->frozen != FROZEN && hs->frozen != THAWING);
|
||||
if (hs->frozen == FREEZING) {
|
||||
/*
|
||||
* If we've received data while this socket is supposed to
|
||||
* be frozen (because the read winhandl.c started before
|
||||
* sk_set_frozen was called has now returned) then buffer
|
||||
* the data for when we unfreeze.
|
||||
*/
|
||||
bufchain_add(&ps->inputdata, data, len);
|
||||
ps->frozen = FROZEN;
|
||||
bufchain_add(&hs->inputdata, data, len);
|
||||
hs->frozen = FROZEN;
|
||||
|
||||
/*
|
||||
* And return a very large backlog, to prevent further
|
||||
@@ -81,7 +78,7 @@ static int handle_gotdata(struct handle *h, void *data, int len)
|
||||
*/
|
||||
return INT_MAX;
|
||||
} else {
|
||||
plug_receive(ps->plug, 0, data, len);
|
||||
plug_receive(hs->plug, 0, data, len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -89,11 +86,11 @@ static int handle_gotdata(struct handle *h, void *data, int len)
|
||||
|
||||
static int handle_stderr(struct handle *h, void *data, int len)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) handle_get_privdata(h);
|
||||
HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
log_proxy_stderr(ps->plug, &ps->stderrdata, data, len);
|
||||
log_proxy_stderr(hs->plug, &hs->stderrdata, data, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -101,71 +98,71 @@ static int handle_stderr(struct handle *h, void *data, int len)
|
||||
|
||||
static void handle_sentdata(struct handle *h, int new_backlog)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) handle_get_privdata(h);
|
||||
HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
|
||||
|
||||
if (new_backlog < 0) {
|
||||
/* Special case: this is actually reporting an error writing
|
||||
* to the underlying handle, and our input value is the error
|
||||
* code itself, negated. */
|
||||
plug_closing(ps->plug, win_strerror(-new_backlog), -new_backlog, 0);
|
||||
plug_closing(hs->plug, win_strerror(-new_backlog), -new_backlog, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
plug_sent(ps->plug, new_backlog);
|
||||
plug_sent(hs->plug, new_backlog);
|
||||
}
|
||||
|
||||
static Plug sk_handle_plug(Socket s, Plug p)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) s;
|
||||
Plug ret = ps->plug;
|
||||
HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt);
|
||||
Plug ret = hs->plug;
|
||||
if (p)
|
||||
ps->plug = p;
|
||||
hs->plug = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sk_handle_close(Socket s)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) s;
|
||||
HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt);
|
||||
|
||||
if (ps->defer_close) {
|
||||
ps->deferred_close = TRUE;
|
||||
if (hs->defer_close) {
|
||||
hs->deferred_close = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MPEXT
|
||||
// WinSCP core uses do_select as signalization of connection up/down
|
||||
do_select(ps->plug, INVALID_SOCKET, 0);
|
||||
do_select(hs->plug, INVALID_SOCKET, 0);
|
||||
#endif
|
||||
|
||||
handle_free(ps->send_h);
|
||||
handle_free(ps->recv_h);
|
||||
CloseHandle(ps->send_H);
|
||||
if (ps->recv_H != ps->send_H)
|
||||
CloseHandle(ps->recv_H);
|
||||
handle_free(hs->send_h);
|
||||
handle_free(hs->recv_h);
|
||||
CloseHandle(hs->send_H);
|
||||
if (hs->recv_H != hs->send_H)
|
||||
CloseHandle(hs->recv_H);
|
||||
bufchain_clear(&hs->inputdata);
|
||||
bufchain_clear(&hs->stderrdata);
|
||||
#ifdef MPEXT
|
||||
if (ps->stderr_h)
|
||||
if (hs->stderr_h)
|
||||
{
|
||||
handle_free(ps->stderr_h);
|
||||
handle_free(hs->stderr_h);
|
||||
}
|
||||
if (ps->stderr_H)
|
||||
if (hs->stderr_H)
|
||||
{
|
||||
CloseHandle(ps->stderr_H);
|
||||
CloseHandle(hs->stderr_H);
|
||||
}
|
||||
#endif
|
||||
bufchain_clear(&ps->inputdata);
|
||||
bufchain_clear(&ps->stderrdata);
|
||||
|
||||
sfree(ps);
|
||||
sfree(hs);
|
||||
}
|
||||
|
||||
static int sk_handle_write(Socket s, const char *data, int len)
|
||||
static int sk_handle_write(Socket s, const void *data, int len)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) s;
|
||||
HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt);
|
||||
|
||||
return handle_write(ps->send_h, data, len);
|
||||
return handle_write(hs->send_h, data, len);
|
||||
}
|
||||
|
||||
static int sk_handle_write_oob(Socket s, const char *data, int len)
|
||||
static int sk_handle_write_oob(Socket s, const void *data, int len)
|
||||
{
|
||||
/*
|
||||
* oob data is treated as inband; nasty, but nothing really
|
||||
@@ -176,20 +173,20 @@ static int sk_handle_write_oob(Socket s, const char *data, int len)
|
||||
|
||||
static void sk_handle_write_eof(Socket s)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) s;
|
||||
HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt);
|
||||
|
||||
handle_write_eof(ps->send_h);
|
||||
handle_write_eof(hs->send_h);
|
||||
}
|
||||
|
||||
static void sk_handle_flush(Socket s)
|
||||
{
|
||||
/* Handle_Socket ps = (Handle_Socket) s; */
|
||||
/* HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt); */
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static void handle_socket_unfreeze(void *psv)
|
||||
static void handle_socket_unfreeze(void *hsv)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) psv;
|
||||
HandleSocket *hs = (HandleSocket *)hsv;
|
||||
void *data;
|
||||
int len;
|
||||
|
||||
@@ -197,49 +194,49 @@ static void handle_socket_unfreeze(void *psv)
|
||||
* If we've been put into a state other than THAWING since the
|
||||
* last callback, then we're done.
|
||||
*/
|
||||
if (ps->frozen != THAWING)
|
||||
if (hs->frozen != THAWING)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Get some of the data we've buffered.
|
||||
*/
|
||||
bufchain_prefix(&ps->inputdata, &data, &len);
|
||||
bufchain_prefix(&hs->inputdata, &data, &len);
|
||||
assert(len > 0);
|
||||
|
||||
/*
|
||||
* Hand it off to the plug. Be careful of re-entrance - that might
|
||||
* have the effect of trying to close this socket.
|
||||
*/
|
||||
ps->defer_close = TRUE;
|
||||
plug_receive(ps->plug, 0, data, len);
|
||||
bufchain_consume(&ps->inputdata, len);
|
||||
ps->defer_close = FALSE;
|
||||
if (ps->deferred_close) {
|
||||
sk_handle_close(ps);
|
||||
hs->defer_close = TRUE;
|
||||
plug_receive(hs->plug, 0, data, len);
|
||||
bufchain_consume(&hs->inputdata, len);
|
||||
hs->defer_close = FALSE;
|
||||
if (hs->deferred_close) {
|
||||
sk_handle_close(&hs->sockvt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bufchain_size(&ps->inputdata) > 0) {
|
||||
if (bufchain_size(&hs->inputdata) > 0) {
|
||||
/*
|
||||
* If there's still data in our buffer, stay in THAWING state,
|
||||
* and reschedule ourself.
|
||||
*/
|
||||
queue_toplevel_callback(handle_socket_unfreeze, ps);
|
||||
queue_toplevel_callback(handle_socket_unfreeze, hs);
|
||||
} else {
|
||||
/*
|
||||
* Otherwise, we've successfully thawed!
|
||||
*/
|
||||
ps->frozen = UNFROZEN;
|
||||
handle_unthrottle(ps->recv_h, 0);
|
||||
hs->frozen = UNFROZEN;
|
||||
handle_unthrottle(hs->recv_h, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void sk_handle_set_frozen(Socket s, int is_frozen)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) s;
|
||||
HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt);
|
||||
|
||||
if (is_frozen) {
|
||||
switch (ps->frozen) {
|
||||
switch (hs->frozen) {
|
||||
case FREEZING:
|
||||
case FROZEN:
|
||||
return; /* nothing to do */
|
||||
@@ -251,7 +248,7 @@ static void sk_handle_set_frozen(Socket s, int is_frozen)
|
||||
* throttled, so just return to FROZEN state. The toplevel
|
||||
* callback will notice and disable itself.
|
||||
*/
|
||||
ps->frozen = FROZEN;
|
||||
hs->frozen = FROZEN;
|
||||
break;
|
||||
|
||||
case UNFROZEN:
|
||||
@@ -259,11 +256,11 @@ static void sk_handle_set_frozen(Socket s, int is_frozen)
|
||||
* The normal case. Go to FREEZING, and expect one more
|
||||
* load of data from winhandl if we're unlucky.
|
||||
*/
|
||||
ps->frozen = FREEZING;
|
||||
hs->frozen = FREEZING;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (ps->frozen) {
|
||||
switch (hs->frozen) {
|
||||
case UNFROZEN:
|
||||
case THAWING:
|
||||
return; /* nothing to do */
|
||||
@@ -274,8 +271,8 @@ static void sk_handle_set_frozen(Socket s, int is_frozen)
|
||||
* we were frozen, then we'll still be in this state and
|
||||
* can just unfreeze in the trivial way.
|
||||
*/
|
||||
assert(bufchain_size(&ps->inputdata) == 0);
|
||||
ps->frozen = UNFROZEN;
|
||||
assert(bufchain_size(&hs->inputdata) == 0);
|
||||
hs->frozen = UNFROZEN;
|
||||
break;
|
||||
|
||||
case FROZEN:
|
||||
@@ -283,21 +280,21 @@ static void sk_handle_set_frozen(Socket s, int is_frozen)
|
||||
* If we have buffered data, go to THAWING and start
|
||||
* releasing it in top-level callbacks.
|
||||
*/
|
||||
ps->frozen = THAWING;
|
||||
queue_toplevel_callback(handle_socket_unfreeze, ps);
|
||||
hs->frozen = THAWING;
|
||||
queue_toplevel_callback(handle_socket_unfreeze, hs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *sk_handle_socket_error(Socket s)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) s;
|
||||
return ps->error;
|
||||
HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt);
|
||||
return hs->error;
|
||||
}
|
||||
|
||||
static char *sk_handle_peer_info(Socket s)
|
||||
{
|
||||
Handle_Socket ps = (Handle_Socket) s;
|
||||
HandleSocket *hs = FROMFIELD(s, HandleSocket, sockvt);
|
||||
ULONG pid;
|
||||
static HMODULE kernel32_module;
|
||||
DECL_WINDOWS_FUNCTION(static, BOOL, GetNamedPipeClientProcessId,
|
||||
@@ -324,53 +321,53 @@ static char *sk_handle_peer_info(Socket s)
|
||||
* to log what we can find out about the client end.
|
||||
*/
|
||||
if (p_GetNamedPipeClientProcessId &&
|
||||
p_GetNamedPipeClientProcessId(ps->send_H, &pid))
|
||||
p_GetNamedPipeClientProcessId(hs->send_H, &pid))
|
||||
return dupprintf("process id %lu", (unsigned long)pid);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const Socket_vtable HandleSocket_sockvt = {
|
||||
sk_handle_plug,
|
||||
sk_handle_close,
|
||||
sk_handle_write,
|
||||
sk_handle_write_oob,
|
||||
sk_handle_write_eof,
|
||||
sk_handle_flush,
|
||||
sk_handle_set_frozen,
|
||||
sk_handle_socket_error,
|
||||
sk_handle_peer_info,
|
||||
};
|
||||
|
||||
Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H,
|
||||
Plug plug, int overlapped)
|
||||
{
|
||||
static const struct socket_function_table socket_fn_table = {
|
||||
sk_handle_plug,
|
||||
sk_handle_close,
|
||||
sk_handle_write,
|
||||
sk_handle_write_oob,
|
||||
sk_handle_write_eof,
|
||||
sk_handle_flush,
|
||||
sk_handle_set_frozen,
|
||||
sk_handle_socket_error,
|
||||
sk_handle_peer_info,
|
||||
};
|
||||
|
||||
Handle_Socket ret;
|
||||
HandleSocket *hs;
|
||||
int flags = (overlapped ? HANDLE_FLAG_OVERLAPPED : 0);
|
||||
|
||||
ret = snew(struct Socket_handle_tag);
|
||||
ret->fn = &socket_fn_table;
|
||||
ret->plug = plug;
|
||||
ret->error = NULL;
|
||||
ret->frozen = UNFROZEN;
|
||||
bufchain_init(&ret->inputdata);
|
||||
bufchain_init(&ret->stderrdata);
|
||||
hs = snew(HandleSocket);
|
||||
hs->sockvt = &HandleSocket_sockvt;
|
||||
hs->plug = plug;
|
||||
hs->error = NULL;
|
||||
hs->frozen = UNFROZEN;
|
||||
bufchain_init(&hs->inputdata);
|
||||
bufchain_init(&hs->stderrdata);
|
||||
|
||||
ret->recv_H = recv_H;
|
||||
ret->recv_h = handle_input_new(ret->recv_H, handle_gotdata, ret, flags);
|
||||
ret->send_H = send_H;
|
||||
ret->send_h = handle_output_new(ret->send_H, handle_sentdata, ret, flags);
|
||||
ret->stderr_H = stderr_H;
|
||||
if (ret->stderr_H)
|
||||
ret->stderr_h = handle_input_new(ret->stderr_H, handle_stderr,
|
||||
ret, flags);
|
||||
hs->recv_H = recv_H;
|
||||
hs->recv_h = handle_input_new(hs->recv_H, handle_gotdata, hs, flags);
|
||||
hs->send_H = send_H;
|
||||
hs->send_h = handle_output_new(hs->send_H, handle_sentdata, hs, flags);
|
||||
hs->stderr_H = stderr_H;
|
||||
if (hs->stderr_H)
|
||||
hs->stderr_h = handle_input_new(hs->stderr_H, handle_stderr,
|
||||
hs, flags);
|
||||
|
||||
ret->defer_close = ret->deferred_close = FALSE;
|
||||
hs->defer_close = hs->deferred_close = FALSE;
|
||||
|
||||
#ifdef MPEXT
|
||||
// WinSCP core uses do_select as signalization of connection up/down
|
||||
do_select(plug, INVALID_SOCKET, 1);
|
||||
#endif
|
||||
|
||||
return (Socket) ret;
|
||||
return &hs->sockvt;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "putty.h"
|
||||
#ifndef SECURITY_WIN32
|
||||
#define SECURITY_WIN32
|
||||
@@ -13,7 +14,7 @@
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
OSVERSIONINFO osVersion;
|
||||
DWORD osMajorVersion, osMinorVersion, osPlatformId;
|
||||
|
||||
char *platform_get_x_display(void) {
|
||||
/* We may as well check for DISPLAY in case it's useful. */
|
||||
@@ -53,25 +54,13 @@ void filename_free(Filename *fn)
|
||||
sfree(fn);
|
||||
}
|
||||
|
||||
int filename_serialise(const Filename *f, void *vdata)
|
||||
void filename_serialise(BinarySink *bs, const Filename *f)
|
||||
{
|
||||
char *data = (char *)vdata;
|
||||
int len = strlen(f->path) + 1; /* include trailing NUL */
|
||||
if (data) {
|
||||
strcpy(data, f->path);
|
||||
}
|
||||
return len;
|
||||
put_asciz(bs, f->path);
|
||||
}
|
||||
Filename *filename_deserialise(void *vdata, int maxsize, int *used)
|
||||
Filename *filename_deserialise(BinarySource *src)
|
||||
{
|
||||
char *data = (char *)vdata;
|
||||
char *end;
|
||||
end = memchr(data, '\0', maxsize);
|
||||
if (!end)
|
||||
return NULL;
|
||||
end++;
|
||||
*used = end - data;
|
||||
return filename_from_str(data);
|
||||
return filename_from_str(get_asciz(src));
|
||||
}
|
||||
|
||||
char filename_char_sanitise(char c)
|
||||
@@ -143,6 +132,7 @@ char *get_username(void)
|
||||
sspicli.dll WITHOUT proper path sanitizing, so better
|
||||
load it properly before */
|
||||
HMODULE sspicli = load_system32_dll("sspicli.dll");
|
||||
(void)sspicli; /* squash compiler warning about unused variable */
|
||||
GET_WINDOWS_FUNCTION(secur32, GetUserNameExA);
|
||||
tried_usernameex = TRUE;
|
||||
}
|
||||
@@ -234,11 +224,41 @@ void dll_hijacking_protection(void)
|
||||
}
|
||||
}
|
||||
|
||||
BOOL init_winver(void)
|
||||
void init_winver(void)
|
||||
{
|
||||
OSVERSIONINFO osVersion;
|
||||
static HMODULE kernel32_module;
|
||||
DECL_WINDOWS_FUNCTION(static, BOOL, GetVersionExA, (LPOSVERSIONINFO));
|
||||
|
||||
if (!kernel32_module) {
|
||||
kernel32_module = load_system32_dll("kernel32.dll");
|
||||
/* Deliberately don't type-check this function, because that
|
||||
* would involve using its declaration in a header file which
|
||||
* triggers a deprecation warning. I know it's deprecated (see
|
||||
* below) and don't need telling. */
|
||||
GET_WINDOWS_FUNCTION_NO_TYPECHECK(kernel32_module, GetVersionExA);
|
||||
}
|
||||
|
||||
ZeroMemory(&osVersion, sizeof(osVersion));
|
||||
osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
||||
return GetVersionEx ( (OSVERSIONINFO *) &osVersion);
|
||||
if (p_GetVersionExA && p_GetVersionExA(&osVersion)) {
|
||||
osMajorVersion = osVersion.dwMajorVersion;
|
||||
osMinorVersion = osVersion.dwMinorVersion;
|
||||
osPlatformId = osVersion.dwPlatformId;
|
||||
} else {
|
||||
/*
|
||||
* GetVersionEx is deprecated, so allow for it perhaps going
|
||||
* away in future API versions. If it's not there, simply
|
||||
* assume that's because Windows is too _new_, so fill in the
|
||||
* variables we care about to a value that will always compare
|
||||
* higher than any given test threshold.
|
||||
*
|
||||
* Normally we should be checking against the presence of a
|
||||
* specific function if possible in any case.
|
||||
*/
|
||||
osMajorVersion = osMinorVersion = UINT_MAX; /* a very high number */
|
||||
osPlatformId = VER_PLATFORM_WIN32_NT; /* not Win32s or Win95-like */
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MPEXT
|
||||
@@ -606,31 +626,51 @@ void fontspec_free(FontSpec *f)
|
||||
sfree(f->name);
|
||||
sfree(f);
|
||||
}
|
||||
int fontspec_serialise(FontSpec *f, void *vdata)
|
||||
void fontspec_serialise(BinarySink *bs, FontSpec *f)
|
||||
{
|
||||
char *data = (char *)vdata;
|
||||
int len = strlen(f->name) + 1; /* include trailing NUL */
|
||||
if (data) {
|
||||
strcpy(data, f->name);
|
||||
PUT_32BIT_MSB_FIRST(data + len, f->isbold);
|
||||
PUT_32BIT_MSB_FIRST(data + len + 4, f->height);
|
||||
PUT_32BIT_MSB_FIRST(data + len + 8, f->charset);
|
||||
put_asciz(bs, f->name);
|
||||
put_uint32(bs, f->isbold);
|
||||
put_uint32(bs, f->height);
|
||||
put_uint32(bs, f->charset);
|
||||
}
|
||||
FontSpec *fontspec_deserialise(BinarySource *src)
|
||||
{
|
||||
const char *name = get_asciz(src);
|
||||
unsigned isbold = get_uint32(src);
|
||||
unsigned height = get_uint32(src);
|
||||
unsigned charset = get_uint32(src);
|
||||
return fontspec_new(name, isbold, height, charset);
|
||||
}
|
||||
|
||||
int open_for_write_would_lose_data(const Filename *fn)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
||||
if (!GetFileAttributesEx(fn->path, GetFileExInfoStandard, &attrs)) {
|
||||
/*
|
||||
* Generally, if we don't identify a specific reason why we
|
||||
* should return true from this function, we return false, and
|
||||
* let the subsequent attempt to open the file for real give a
|
||||
* more useful error message.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
return len + 12; /* also include three 4-byte ints */
|
||||
}
|
||||
FontSpec *fontspec_deserialise(void *vdata, int maxsize, int *used)
|
||||
{
|
||||
char *data = (char *)vdata;
|
||||
char *end;
|
||||
if (maxsize < 13)
|
||||
return NULL;
|
||||
end = memchr(data, '\0', maxsize-12);
|
||||
if (!end)
|
||||
return NULL;
|
||||
end++;
|
||||
*used = end - data + 12;
|
||||
return fontspec_new(data,
|
||||
GET_32BIT_MSB_FIRST(end),
|
||||
GET_32BIT_MSB_FIRST(end + 4),
|
||||
GET_32BIT_MSB_FIRST(end + 8));
|
||||
if (attrs.dwFileAttributes & (FILE_ATTRIBUTE_DEVICE |
|
||||
FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
/*
|
||||
* File is something other than an ordinary disk file, so
|
||||
* opening it for writing will not cause truncation. (It may
|
||||
* not _succeed_ either, but that's not our problem here!)
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
if (attrs.nFileSizeHigh == 0 && attrs.nFileSizeLow == 0) {
|
||||
/*
|
||||
* File is zero-length (or may be a named pipe, which
|
||||
* dwFileAttributes can't tell apart from a regular file), so
|
||||
* opening it for writing won't truncate any data away because
|
||||
* there's nothing to truncate anyway.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -39,16 +39,6 @@ const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
|
||||
#define ipv4_is_loopback(addr) \
|
||||
((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)
|
||||
|
||||
/*
|
||||
* We used to typedef struct Socket_tag *Socket.
|
||||
*
|
||||
* Since we have made the networking abstraction slightly more
|
||||
* abstract, Socket no longer means a tcp socket (it could mean
|
||||
* an ssl socket). So now we must use Actual_Socket when we know
|
||||
* we are talking about a tcp socket.
|
||||
*/
|
||||
typedef struct Socket_tag *Actual_Socket;
|
||||
|
||||
/*
|
||||
* Mutable state that goes with a SockAddr: stores information
|
||||
* about where in the list of candidate IP(v*) addresses we've
|
||||
@@ -62,9 +52,8 @@ struct SockAddrStep_tag {
|
||||
int curraddr;
|
||||
};
|
||||
|
||||
struct Socket_tag {
|
||||
const struct socket_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
typedef struct NetSocket NetSocket;
|
||||
struct NetSocket {
|
||||
const char *error;
|
||||
SOCKET s;
|
||||
Plug plug;
|
||||
@@ -89,7 +78,9 @@ struct Socket_tag {
|
||||
* example. So here we define `parent' and `child' pointers to
|
||||
* track this link.
|
||||
*/
|
||||
Actual_Socket parent, child;
|
||||
NetSocket *parent, *child;
|
||||
|
||||
const Socket_vtable *sockvt;
|
||||
};
|
||||
|
||||
struct SockAddr_tag {
|
||||
@@ -137,7 +128,7 @@ static tree234 *sktree;
|
||||
|
||||
static int cmpfortree(void *av, void *bv)
|
||||
{
|
||||
Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;
|
||||
NetSocket *a = (NetSocket *)av, *b = (NetSocket *)bv;
|
||||
unsigned long as = (unsigned long) a->s, bs = (unsigned long) b->s;
|
||||
if (as < bs)
|
||||
return -1;
|
||||
@@ -152,7 +143,7 @@ static int cmpfortree(void *av, void *bv)
|
||||
|
||||
static int cmpforsearch(void *av, void *bv)
|
||||
{
|
||||
Actual_Socket b = (Actual_Socket) bv;
|
||||
NetSocket *b = (NetSocket *)bv;
|
||||
uintptr_t as = (uintptr_t) av, bs = (uintptr_t) b->s;
|
||||
if (as < bs)
|
||||
return -1;
|
||||
@@ -209,8 +200,8 @@ DECL_WINDOWS_FUNCTION(static, int, getaddrinfo,
|
||||
DECL_WINDOWS_FUNCTION(static, void, freeaddrinfo, (struct addrinfo *res));
|
||||
DECL_WINDOWS_FUNCTION(static, int, getnameinfo,
|
||||
(const struct sockaddr FAR * sa, socklen_t salen,
|
||||
char FAR * host, size_t hostlen, char FAR * serv,
|
||||
size_t servlen, int flags));
|
||||
char FAR * host, DWORD hostlen, char FAR * serv,
|
||||
DWORD servlen, int flags));
|
||||
DECL_WINDOWS_FUNCTION(static, char *, gai_strerror, (int ecode));
|
||||
DECL_WINDOWS_FUNCTION(static, int, WSAAddressToStringA,
|
||||
(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFO,
|
||||
@@ -266,7 +257,8 @@ void sk_init(void)
|
||||
}
|
||||
if (!winsock_module)
|
||||
{
|
||||
fatalbox("Unable to load any WinSock library");
|
||||
modalfatalbox("Unable to load any WinSock library");
|
||||
|
||||
}
|
||||
|
||||
#ifndef NO_IPV6
|
||||
@@ -313,7 +305,11 @@ void sk_init(void)
|
||||
|
||||
GET_WINDOWS_FUNCTION(winsock_module, WSAAsyncSelect);
|
||||
GET_WINDOWS_FUNCTION(winsock_module, WSAEventSelect);
|
||||
GET_WINDOWS_FUNCTION(winsock_module, select);
|
||||
/* We don't type-check select because at least some MinGW versions
|
||||
* of the Windows API headers seem to disagree with the
|
||||
* documentation on whether the 'struct timeval *' pointer is
|
||||
* const or not. */
|
||||
GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, select);
|
||||
GET_WINDOWS_FUNCTION(winsock_module, WSAGetLastError);
|
||||
GET_WINDOWS_FUNCTION(winsock_module, WSAEnumNetworkEvents);
|
||||
GET_WINDOWS_FUNCTION(winsock_module, WSAStartup);
|
||||
@@ -324,7 +320,7 @@ void sk_init(void)
|
||||
GET_WINDOWS_FUNCTION(winsock_module, htonl);
|
||||
GET_WINDOWS_FUNCTION(winsock_module, htons);
|
||||
GET_WINDOWS_FUNCTION(winsock_module, ntohs);
|
||||
GET_WINDOWS_FUNCTION(winsock_module, gethostname);
|
||||
GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gethostname);
|
||||
#else
|
||||
/* The toolchain I use for Windows Coverity builds doesn't know
|
||||
* the type signatures of these */
|
||||
@@ -365,7 +361,7 @@ void sk_init(void)
|
||||
if (!sk_startup(2,2) &&
|
||||
!sk_startup(2,0) &&
|
||||
!sk_startup(1,1)) {
|
||||
fatalbox("Unable to initialise WinSock");
|
||||
modalfatalbox("Unable to initialise WinSock");
|
||||
}
|
||||
|
||||
sktree = newtree234(cmpfortree);
|
||||
@@ -373,7 +369,7 @@ void sk_init(void)
|
||||
|
||||
void sk_cleanup(void)
|
||||
{
|
||||
Actual_Socket s;
|
||||
NetSocket *s;
|
||||
int i;
|
||||
|
||||
if (sktree) {
|
||||
@@ -936,16 +932,16 @@ SockAddr sk_addr_dup(SockAddr addr)
|
||||
return addr;
|
||||
}
|
||||
|
||||
static Plug sk_tcp_plug(Socket sock, Plug p)
|
||||
static Plug sk_net_plug(Socket sock, Plug p)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
NetSocket *s = FROMFIELD(sock, NetSocket, sockvt);
|
||||
Plug ret = s->plug;
|
||||
if (p)
|
||||
s->plug = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sk_tcp_flush(Socket s)
|
||||
static void sk_net_flush(Socket s)
|
||||
{
|
||||
/*
|
||||
* We send data to the socket as soon as we can anyway,
|
||||
@@ -953,13 +949,13 @@ static void sk_tcp_flush(Socket s)
|
||||
*/
|
||||
}
|
||||
|
||||
static void sk_tcp_close(Socket s);
|
||||
static int sk_tcp_write(Socket s, const char *data, int len);
|
||||
static int sk_tcp_write_oob(Socket s, const char *data, int len);
|
||||
static void sk_tcp_write_eof(Socket s);
|
||||
static void sk_tcp_set_frozen(Socket s, int is_frozen);
|
||||
static const char *sk_tcp_socket_error(Socket s);
|
||||
static char *sk_tcp_peer_info(Socket s);
|
||||
static void sk_net_close(Socket s);
|
||||
static int sk_net_write(Socket s, const void *data, int len);
|
||||
static int sk_net_write_oob(Socket s, const void *data, int len);
|
||||
static void sk_net_write_eof(Socket s);
|
||||
static void sk_net_set_frozen(Socket s, int is_frozen);
|
||||
static const char *sk_net_socket_error(Socket s);
|
||||
static char *sk_net_peer_info(Socket s);
|
||||
|
||||
#ifdef MPEXT
|
||||
extern char *do_select(Plug plug, SOCKET skt, int startup);
|
||||
@@ -967,29 +963,29 @@ extern char *do_select(Plug plug, SOCKET skt, int startup);
|
||||
extern char *do_select(SOCKET skt, int startup);
|
||||
#endif
|
||||
|
||||
static Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug)
|
||||
{
|
||||
static const struct socket_function_table fn_table = {
|
||||
sk_tcp_plug,
|
||||
sk_tcp_close,
|
||||
sk_tcp_write,
|
||||
sk_tcp_write_oob,
|
||||
sk_tcp_write_eof,
|
||||
sk_tcp_flush,
|
||||
sk_tcp_set_frozen,
|
||||
sk_tcp_socket_error,
|
||||
sk_tcp_peer_info,
|
||||
};
|
||||
static const Socket_vtable NetSocket_sockvt = {
|
||||
sk_net_plug,
|
||||
sk_net_close,
|
||||
sk_net_write,
|
||||
sk_net_write_oob,
|
||||
sk_net_write_eof,
|
||||
sk_net_flush,
|
||||
sk_net_set_frozen,
|
||||
sk_net_socket_error,
|
||||
sk_net_peer_info,
|
||||
};
|
||||
|
||||
static Socket sk_net_accept(accept_ctx_t ctx, Plug plug)
|
||||
{
|
||||
DWORD err;
|
||||
char *errstr;
|
||||
Actual_Socket ret;
|
||||
NetSocket *ret;
|
||||
|
||||
/*
|
||||
* Create Socket structure.
|
||||
* Create NetSocket structure.
|
||||
*/
|
||||
ret = snew(struct Socket_tag);
|
||||
ret->fn = &fn_table;
|
||||
ret = snew(NetSocket);
|
||||
ret->sockvt = &NetSocket_sockvt;
|
||||
ret->error = NULL;
|
||||
ret->plug = plug;
|
||||
bufchain_init(&ret->output_data);
|
||||
@@ -1008,7 +1004,7 @@ static Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug)
|
||||
if (ret->s == INVALID_SOCKET) {
|
||||
err = p_WSAGetLastError();
|
||||
ret->error = winsock_error_string(err);
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
ret->oobinline = 0;
|
||||
@@ -1022,15 +1018,15 @@ static Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug)
|
||||
#endif
|
||||
if (errstr) {
|
||||
ret->error = errstr;
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
add234(sktree, ret);
|
||||
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
static DWORD try_connect(Actual_Socket sock,
|
||||
static DWORD try_connect(NetSocket *sock,
|
||||
#ifdef MPEXT
|
||||
int timeout,
|
||||
int sndbuf
|
||||
@@ -1298,26 +1294,14 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
||||
#endif
|
||||
)
|
||||
{
|
||||
static const struct socket_function_table fn_table = {
|
||||
sk_tcp_plug,
|
||||
sk_tcp_close,
|
||||
sk_tcp_write,
|
||||
sk_tcp_write_oob,
|
||||
sk_tcp_write_eof,
|
||||
sk_tcp_flush,
|
||||
sk_tcp_set_frozen,
|
||||
sk_tcp_socket_error,
|
||||
sk_tcp_peer_info,
|
||||
};
|
||||
|
||||
Actual_Socket ret;
|
||||
NetSocket *ret;
|
||||
DWORD err;
|
||||
|
||||
/*
|
||||
* Create Socket structure.
|
||||
* Create NetSocket structure.
|
||||
*/
|
||||
ret = snew(struct Socket_tag);
|
||||
ret->fn = &fn_table;
|
||||
ret = snew(NetSocket);
|
||||
ret->sockvt = &NetSocket_sockvt;
|
||||
ret->error = NULL;
|
||||
ret->plug = plug;
|
||||
bufchain_init(&ret->output_data);
|
||||
@@ -1351,24 +1335,12 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
||||
);
|
||||
} while (err && sk_nextaddr(ret->addr, &ret->step));
|
||||
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
Socket sk_newlistener(const char *srcaddr, int port, Plug plug,
|
||||
int local_host_only, int orig_address_family)
|
||||
{
|
||||
static const struct socket_function_table fn_table = {
|
||||
sk_tcp_plug,
|
||||
sk_tcp_close,
|
||||
sk_tcp_write,
|
||||
sk_tcp_write_oob,
|
||||
sk_tcp_write_eof,
|
||||
sk_tcp_flush,
|
||||
sk_tcp_set_frozen,
|
||||
sk_tcp_socket_error,
|
||||
sk_tcp_peer_info,
|
||||
};
|
||||
|
||||
SOCKET s;
|
||||
#ifndef NO_IPV6
|
||||
SOCKADDR_IN6 a6;
|
||||
@@ -1377,17 +1349,17 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug,
|
||||
|
||||
DWORD err;
|
||||
char *errstr;
|
||||
Actual_Socket ret;
|
||||
NetSocket *ret;
|
||||
int retcode;
|
||||
int on = 1;
|
||||
|
||||
int address_family;
|
||||
|
||||
/*
|
||||
* Create Socket structure.
|
||||
* Create NetSocket structure.
|
||||
*/
|
||||
ret = snew(struct Socket_tag);
|
||||
ret->fn = &fn_table;
|
||||
ret = snew(NetSocket);
|
||||
ret->sockvt = &NetSocket_sockvt;
|
||||
ret->error = NULL;
|
||||
ret->plug = plug;
|
||||
bufchain_init(&ret->output_data);
|
||||
@@ -1429,10 +1401,10 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug,
|
||||
if (s == INVALID_SOCKET) {
|
||||
err = p_WSAGetLastError();
|
||||
ret->error = winsock_error_string(err);
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
|
||||
SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
ret->oobinline = 0;
|
||||
|
||||
@@ -1515,14 +1487,14 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug,
|
||||
if (err) {
|
||||
p_closesocket(s);
|
||||
ret->error = winsock_error_string(err);
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
|
||||
if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) {
|
||||
p_closesocket(s);
|
||||
ret->error = winsock_error_string(p_WSAGetLastError());
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
/* Set up a select mechanism. This could be an AsyncSelect on a
|
||||
@@ -1535,7 +1507,7 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug,
|
||||
if (errstr) {
|
||||
p_closesocket(s);
|
||||
ret->error = errstr;
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
add234(sktree, ret);
|
||||
@@ -1546,36 +1518,35 @@ Socket sk_newlistener(const char *srcaddr, int port, Plug plug,
|
||||
* IPv6 listening socket and link it to this one.
|
||||
*/
|
||||
if (address_family == AF_INET && orig_address_family == ADDRTYPE_UNSPEC) {
|
||||
Actual_Socket other;
|
||||
|
||||
other = (Actual_Socket) sk_newlistener(srcaddr, port, plug,
|
||||
local_host_only, ADDRTYPE_IPV6);
|
||||
Socket other = sk_newlistener(srcaddr, port, plug,
|
||||
local_host_only, ADDRTYPE_IPV6);
|
||||
|
||||
if (other) {
|
||||
if (!other->error) {
|
||||
other->parent = ret;
|
||||
ret->child = other;
|
||||
NetSocket *ns = FROMFIELD(other, NetSocket, sockvt);
|
||||
if (!ns->error) {
|
||||
ns->parent = ret;
|
||||
ret->child = ns;
|
||||
} else {
|
||||
sfree(other);
|
||||
sfree(ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return (Socket) ret;
|
||||
return &ret->sockvt;
|
||||
}
|
||||
|
||||
static void sk_tcp_close(Socket sock)
|
||||
static void sk_net_close(Socket sock)
|
||||
{
|
||||
#ifdef MPEXT
|
||||
extern char *do_select(Plug plug, SOCKET skt, int startup);
|
||||
#else
|
||||
extern char *do_select(SOCKET skt, int startup);
|
||||
#endif
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
NetSocket *s = FROMFIELD(sock, NetSocket, sockvt);
|
||||
|
||||
if (s->child)
|
||||
sk_tcp_close((Socket)s->child);
|
||||
sk_net_close(&s->child->sockvt);
|
||||
|
||||
del234(sktree, s);
|
||||
#ifdef MPEXT
|
||||
@@ -1594,7 +1565,7 @@ static void sk_tcp_close(Socket sock)
|
||||
*/
|
||||
static void socket_error_callback(void *vs)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket)vs;
|
||||
NetSocket *s = (NetSocket *)vs;
|
||||
|
||||
/*
|
||||
* Just in case other socket work has caused this socket to vanish
|
||||
@@ -1614,7 +1585,7 @@ static void socket_error_callback(void *vs)
|
||||
* The function which tries to send on a socket once it's deemed
|
||||
* writable.
|
||||
*/
|
||||
void try_send(Actual_Socket s)
|
||||
void try_send(NetSocket *s)
|
||||
{
|
||||
while (s->sending_oob || bufchain_size(&s->output_data) > 0) {
|
||||
int nsent;
|
||||
@@ -1646,26 +1617,20 @@ void try_send(Actual_Socket s)
|
||||
*/
|
||||
s->writable = FALSE;
|
||||
return;
|
||||
} else if (nsent == 0 ||
|
||||
err == WSAECONNABORTED || err == WSAECONNRESET) {
|
||||
} else {
|
||||
/*
|
||||
* If send() returns CONNABORTED or CONNRESET, we
|
||||
* unfortunately can't just call plug_closing(),
|
||||
* because it's quite likely that we're currently
|
||||
* _in_ a call from the code we'd be calling back
|
||||
* to, so we'd have to make half the SSH code
|
||||
* reentrant. Instead we flag a pending error on
|
||||
* the socket, to be dealt with (by calling
|
||||
* plug_closing()) at some suitable future moment.
|
||||
* If send() returns a socket error, we unfortunately
|
||||
* can't just call plug_closing(), because it's quite
|
||||
* likely that we're currently _in_ a call from the
|
||||
* code we'd be calling back to, so we'd have to make
|
||||
* half the SSH code reentrant. Instead we flag a
|
||||
* pending error on the socket, to be dealt with (by
|
||||
* calling plug_closing()) at some suitable future
|
||||
* moment.
|
||||
*/
|
||||
s->pending_error = err;
|
||||
queue_toplevel_callback(socket_error_callback, s);
|
||||
return;
|
||||
} else {
|
||||
/* We're inside the Windows frontend here, so we know
|
||||
* that the frontend handle is unnecessary. */
|
||||
logevent(NULL, winsock_error_string(err));
|
||||
fatalbox("%s", winsock_error_string(err));
|
||||
}
|
||||
} else {
|
||||
if (s->sending_oob) {
|
||||
@@ -1691,9 +1656,9 @@ void try_send(Actual_Socket s)
|
||||
}
|
||||
}
|
||||
|
||||
static int sk_tcp_write(Socket sock, const char *buf, int len)
|
||||
static int sk_net_write(Socket sock, const void *buf, int len)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
NetSocket *s = FROMFIELD(sock, NetSocket, sockvt);
|
||||
|
||||
assert(s->outgoingeof == EOF_NO);
|
||||
|
||||
@@ -1711,9 +1676,9 @@ static int sk_tcp_write(Socket sock, const char *buf, int len)
|
||||
return bufchain_size(&s->output_data);
|
||||
}
|
||||
|
||||
static int sk_tcp_write_oob(Socket sock, const char *buf, int len)
|
||||
static int sk_net_write_oob(Socket sock, const void *buf, int len)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
NetSocket *s = FROMFIELD(sock, NetSocket, sockvt);
|
||||
|
||||
assert(s->outgoingeof == EOF_NO);
|
||||
|
||||
@@ -1734,9 +1699,9 @@ static int sk_tcp_write_oob(Socket sock, const char *buf, int len)
|
||||
return s->sending_oob;
|
||||
}
|
||||
|
||||
static void sk_tcp_write_eof(Socket sock)
|
||||
static void sk_net_write_eof(Socket sock)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
NetSocket *s = FROMFIELD(sock, NetSocket, sockvt);
|
||||
|
||||
assert(s->outgoingeof == EOF_NO);
|
||||
|
||||
@@ -1757,7 +1722,7 @@ void select_result(WPARAM wParam, LPARAM lParam)
|
||||
int ret;
|
||||
DWORD err;
|
||||
char buf[20480]; /* nice big buffer for plenty of speed */
|
||||
Actual_Socket s;
|
||||
NetSocket *s;
|
||||
u_long atmark;
|
||||
|
||||
/* wParam is the socket itself */
|
||||
@@ -1861,12 +1826,8 @@ void select_result(WPARAM wParam, LPARAM lParam)
|
||||
ret = p_recv(s->s, buf, sizeof(buf), MSG_OOB);
|
||||
noise_ultralight(ret);
|
||||
if (ret <= 0) {
|
||||
const char *str = (ret == 0 ? "Internal networking trouble" :
|
||||
winsock_error_string(p_WSAGetLastError()));
|
||||
/* We're inside the Windows frontend here, so we know
|
||||
* that the frontend handle is unnecessary. */
|
||||
logevent(NULL, str);
|
||||
fatalbox("%s", str);
|
||||
int err = p_WSAGetLastError();
|
||||
plug_closing(s->plug, winsock_error_string(err), err, 0);
|
||||
} else {
|
||||
plug_receive(s->plug, 2, buf, ret);
|
||||
}
|
||||
@@ -1933,7 +1894,7 @@ void select_result(WPARAM wParam, LPARAM lParam)
|
||||
#endif
|
||||
{
|
||||
p_closesocket(t); /* dodgy WinSock let nonlocal through */
|
||||
} else if (plug_accepting(s->plug, sk_tcp_accept, actx)) {
|
||||
} else if (plug_accepting(s->plug, sk_net_accept, actx)) {
|
||||
p_closesocket(t); /* denied or error */
|
||||
}
|
||||
}
|
||||
@@ -1949,15 +1910,15 @@ const char *sk_addr_error(SockAddr addr)
|
||||
{
|
||||
return addr->error;
|
||||
}
|
||||
static const char *sk_tcp_socket_error(Socket sock)
|
||||
static const char *sk_net_socket_error(Socket sock)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
NetSocket *s = FROMFIELD(sock, NetSocket, sockvt);
|
||||
return s->error;
|
||||
}
|
||||
|
||||
static char *sk_tcp_peer_info(Socket sock)
|
||||
static char *sk_net_peer_info(Socket sock)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
NetSocket *s = FROMFIELD(sock, NetSocket, sockvt);
|
||||
#ifdef NO_IPV6
|
||||
struct sockaddr_in addr;
|
||||
#else
|
||||
@@ -1987,9 +1948,9 @@ static char *sk_tcp_peer_info(Socket sock)
|
||||
}
|
||||
}
|
||||
|
||||
static void sk_tcp_set_frozen(Socket sock, int is_frozen)
|
||||
static void sk_net_set_frozen(Socket sock, int is_frozen)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
NetSocket *s = FROMFIELD(sock, NetSocket, sockvt);
|
||||
if (s->frozen == is_frozen)
|
||||
return;
|
||||
s->frozen = is_frozen;
|
||||
@@ -2009,7 +1970,7 @@ static void sk_tcp_set_frozen(Socket sock, int is_frozen)
|
||||
|
||||
void socket_reselect_all(void)
|
||||
{
|
||||
Actual_Socket s;
|
||||
NetSocket *s;
|
||||
int i;
|
||||
|
||||
for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
|
||||
@@ -2027,7 +1988,7 @@ void socket_reselect_all(void)
|
||||
*/
|
||||
SOCKET first_socket(int *state)
|
||||
{
|
||||
Actual_Socket s;
|
||||
NetSocket *s;
|
||||
*state = 0;
|
||||
s = index234(sktree, (*state)++);
|
||||
return s ? s->s : INVALID_SOCKET;
|
||||
@@ -2035,13 +1996,13 @@ SOCKET first_socket(int *state)
|
||||
|
||||
SOCKET next_socket(int *state)
|
||||
{
|
||||
Actual_Socket s = index234(sktree, (*state)++);
|
||||
NetSocket *s = index234(sktree, (*state)++);
|
||||
return s ? s->s : INVALID_SOCKET;
|
||||
}
|
||||
|
||||
extern int socket_writable(SOCKET skt)
|
||||
{
|
||||
Actual_Socket s = find234(sktree, (void *)skt, cmpforsearch);
|
||||
NetSocket *s = find234(sktree, (void *)skt, cmpforsearch);
|
||||
|
||||
if (s)
|
||||
return bufchain_size(&s->output_data) > 0;
|
||||
|
||||
@@ -18,6 +18,29 @@ DECL_WINDOWS_FUNCTION(static, BOOL, CryptReleaseContext,
|
||||
(HCRYPTPROV, DWORD));
|
||||
static HMODULE wincrypt_module = NULL;
|
||||
|
||||
int win_read_random(void *buf, unsigned wanted)
|
||||
{
|
||||
int toret = FALSE;
|
||||
HCRYPTPROV crypt_provider;
|
||||
|
||||
if (!wincrypt_module) {
|
||||
wincrypt_module = load_system32_dll("advapi32.dll");
|
||||
GET_WINDOWS_FUNCTION(wincrypt_module, CryptAcquireContextA);
|
||||
GET_WINDOWS_FUNCTION(wincrypt_module, CryptGenRandom);
|
||||
GET_WINDOWS_FUNCTION(wincrypt_module, CryptReleaseContext);
|
||||
}
|
||||
|
||||
if (wincrypt_module && p_CryptAcquireContextA &&
|
||||
p_CryptGenRandom && p_CryptReleaseContext &&
|
||||
p_CryptAcquireContextA(&crypt_provider, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
toret = p_CryptGenRandom(crypt_provider, wanted, buf);
|
||||
p_CryptReleaseContext(crypt_provider, 0);
|
||||
}
|
||||
|
||||
return toret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called once, at PuTTY startup.
|
||||
*/
|
||||
@@ -27,8 +50,8 @@ void noise_get_heavy(void (*func) (void *, int))
|
||||
HANDLE srch;
|
||||
WIN32_FIND_DATA finddata;
|
||||
DWORD pid;
|
||||
HCRYPTPROV crypt_provider;
|
||||
char winpath[MAX_PATH + 3];
|
||||
BYTE buf[32];
|
||||
|
||||
GetWindowsDirectory(winpath, sizeof(winpath));
|
||||
strcat(winpath, "\\*");
|
||||
@@ -43,22 +66,9 @@ void noise_get_heavy(void (*func) (void *, int))
|
||||
pid = GetCurrentProcessId();
|
||||
func(&pid, sizeof(pid));
|
||||
|
||||
if (!wincrypt_module) {
|
||||
wincrypt_module = load_system32_dll("advapi32.dll");
|
||||
GET_WINDOWS_FUNCTION(wincrypt_module, CryptAcquireContextA);
|
||||
GET_WINDOWS_FUNCTION(wincrypt_module, CryptGenRandom);
|
||||
GET_WINDOWS_FUNCTION(wincrypt_module, CryptReleaseContext);
|
||||
}
|
||||
|
||||
if (wincrypt_module && p_CryptAcquireContextA &&
|
||||
p_CryptGenRandom && p_CryptReleaseContext &&
|
||||
p_CryptAcquireContextA(&crypt_provider, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
BYTE buf[32];
|
||||
if (p_CryptGenRandom(crypt_provider, 32, buf)) {
|
||||
func(buf, sizeof(buf));
|
||||
}
|
||||
p_CryptReleaseContext(crypt_provider, 0);
|
||||
if (win_read_random(buf, sizeof(buf))) {
|
||||
func(buf, sizeof(buf));
|
||||
smemclr(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
read_random_seed(func);
|
||||
|
||||
@@ -31,7 +31,7 @@ void agent_cancel_query(agent_pending_query *q)
|
||||
}
|
||||
|
||||
agent_pending_query *agent_query(
|
||||
void *in, int inlen, void **out, int *outlen,
|
||||
strbuf *query, void **out, int *outlen,
|
||||
void (*callback)(void *, void *, int), void *callback_ctx)
|
||||
{
|
||||
HWND hwnd;
|
||||
@@ -47,6 +47,9 @@ agent_pending_query *agent_query(
|
||||
*out = NULL;
|
||||
*outlen = 0;
|
||||
|
||||
if (query->len > AGENT_MAX_MSGLEN)
|
||||
return NULL; /* query too large */
|
||||
|
||||
hwnd = FindWindow("Pageant", "Pageant");
|
||||
if (!hwnd)
|
||||
return NULL; /* *out == NULL, so failure */
|
||||
@@ -93,7 +96,8 @@ agent_pending_query *agent_query(
|
||||
return NULL; /* *out == NULL, so failure */
|
||||
}
|
||||
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
|
||||
memcpy(p, in, inlen);
|
||||
strbuf_finalise_agent_query(query);
|
||||
memcpy(p, query->s, query->len);
|
||||
cds.dwData = AGENT_COPYDATA_ID;
|
||||
cds.cbData = 1 + strlen(mapname);
|
||||
cds.lpData = mapname;
|
||||
|
||||
@@ -23,13 +23,21 @@
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include "tree234.h"
|
||||
|
||||
#ifndef MPEXT
|
||||
#include "winhelp.h"
|
||||
#endif
|
||||
|
||||
#if defined _M_IX86 || defined _M_AMD64
|
||||
#define BUILDINFO_PLATFORM "x86 Windows"
|
||||
#elif defined _M_ARM || defined _M_ARM64
|
||||
#define BUILDINFO_PLATFORM "Arm Windows"
|
||||
#else
|
||||
#define BUILDINFO_PLATFORM "Windows"
|
||||
#endif
|
||||
|
||||
struct Filename {
|
||||
char *path;
|
||||
@@ -62,6 +70,10 @@ struct FontSpec *fontspec_new(const char *name,
|
||||
#define PLATFORM_IS_UTF16 /* enable UTF-16 processing when exchanging
|
||||
* wchar_t strings with environment */
|
||||
|
||||
#define PLATFORM_CLIPBOARDS(X) \
|
||||
X(CLIP_SYSTEM, "system clipboard") \
|
||||
/* end of list */
|
||||
|
||||
/*
|
||||
* Where we can, we use GetWindowLongPtr and friends because they're
|
||||
* more useful on 64-bit platforms, but they're a relatively recent
|
||||
@@ -139,8 +151,6 @@ struct FontSpec *fontspec_new(const char *name,
|
||||
*
|
||||
* (DECL_WINDOWS_FUNCTION works with both these variants.)
|
||||
*/
|
||||
#define TYPECHECK(to_check, to_return) \
|
||||
(sizeof(to_check) ? to_return : to_return)
|
||||
#define DECL_WINDOWS_FUNCTION(linkage, rettype, name, params) \
|
||||
typedef rettype (WINAPI *t_##name) params; \
|
||||
linkage t_##name p_##name
|
||||
@@ -171,13 +181,6 @@ struct FontSpec *fontspec_new(const char *name,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DONE_TYPEDEFS
|
||||
#define DONE_TYPEDEFS
|
||||
typedef struct conf_tag Conf;
|
||||
typedef struct backend_tag Backend;
|
||||
typedef struct terminal_tag Terminal;
|
||||
#endif
|
||||
|
||||
#define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY"
|
||||
#define PUTTY_REG_PARENT "Software\\SimonTatham"
|
||||
#define PUTTY_REG_PARENT_CHILD "PuTTY"
|
||||
@@ -205,9 +208,6 @@ typedef struct terminal_tag Terminal;
|
||||
|
||||
typedef HDC Context;
|
||||
|
||||
typedef unsigned int uint32; /* int is 32-bits on Win32 and Win64. */
|
||||
#define PUTTY_UINT32_DEFINED
|
||||
|
||||
#ifndef NO_GSSAPI
|
||||
/*
|
||||
* GSS-API stuff
|
||||
@@ -253,6 +253,13 @@ void quit_help(HWND hwnd);
|
||||
GLOBAL Terminal *term;
|
||||
GLOBAL void *logctx;
|
||||
|
||||
/*
|
||||
* Windows-specific clipboard helper function shared with windlg.c,
|
||||
* which takes the data string in the system code page instead of
|
||||
* Unicode.
|
||||
*/
|
||||
void write_aclip(void *frontend, int clipboard, char *, int, int);
|
||||
|
||||
#define WM_NETEVENT (WM_APP + 5)
|
||||
|
||||
/*
|
||||
@@ -525,9 +532,9 @@ void show_help(HWND hwnd);
|
||||
/*
|
||||
* Exports from winmisc.c.
|
||||
*/
|
||||
extern OSVERSIONINFO osVersion;
|
||||
GLOBAL DWORD osMajorVersion, osMinorVersion, osPlatformId;
|
||||
void init_winver(void);
|
||||
void dll_hijacking_protection(void);
|
||||
BOOL init_winver(void);
|
||||
HMODULE load_system32_dll(const char *libname);
|
||||
const char *win_strerror(int error);
|
||||
void restrict_process_acl(void);
|
||||
@@ -615,6 +622,11 @@ void remove_session_from_jumplist(const char * const sessionname);
|
||||
void clear_jumplist(void);
|
||||
BOOL set_explicit_app_user_model_id();
|
||||
|
||||
/*
|
||||
* Exports from winnoise.c.
|
||||
*/
|
||||
int win_read_random(void *buf, unsigned wanted); /* returns TRUE on success */
|
||||
|
||||
/*
|
||||
* Extra functions in winstore.c over and above the interface in
|
||||
* storage.h.
|
||||
@@ -638,4 +650,15 @@ int remove_from_jumplist_registry(const char *item);
|
||||
* empty one. */
|
||||
char *get_jumplist_registry_entries(void);
|
||||
|
||||
/*
|
||||
* Windows clipboard-UI wording.
|
||||
*/
|
||||
#define CLIPNAME_IMPLICIT "Last selected text"
|
||||
#define CLIPNAME_EXPLICIT "System clipboard"
|
||||
#define CLIPNAME_EXPLICIT_OBJECT "system clipboard"
|
||||
/* These defaults are the ones PuTTY has historically had */
|
||||
#define CLIPUI_DEFAULT_AUTOCOPY TRUE
|
||||
#define CLIPUI_DEFAULT_MOUSE CLIPUI_EXPLICIT
|
||||
#define CLIPUI_DEFAULT_INS CLIPUI_EXPLICIT
|
||||
|
||||
#endif
|
||||
|
||||
184
source/putty/x11fwd.c
vendored
184
source/putty/x11fwd.c
vendored
@@ -27,8 +27,6 @@ struct XDMSeen {
|
||||
};
|
||||
|
||||
struct X11Connection {
|
||||
const struct plug_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
unsigned char firstpkt[12]; /* first X data packet */
|
||||
tree234 *authtree;
|
||||
struct X11Display *disp;
|
||||
@@ -42,6 +40,8 @@ struct X11Connection {
|
||||
int peer_port;
|
||||
struct ssh_channel *c; /* channel structure held by ssh.c */
|
||||
Socket s;
|
||||
|
||||
const Plug_vtable *plugvt;
|
||||
};
|
||||
|
||||
static int xdmseen_cmp(void *a, void *b)
|
||||
@@ -52,22 +52,6 @@ static int xdmseen_cmp(void *a, void *b)
|
||||
memcmp(sa->clientid, sb->clientid, sizeof(sa->clientid));
|
||||
}
|
||||
|
||||
/* Do-nothing "plug" implementation, used by x11_setup_display() when it
|
||||
* creates a trial connection (and then immediately closes it).
|
||||
* XXX: bit out of place here, could in principle live in a platform-
|
||||
* independent network.c or something */
|
||||
static void dummy_plug_log(Plug p, int type, SockAddr addr, int port,
|
||||
const char *error_msg, int error_code) { }
|
||||
static void dummy_plug_closing
|
||||
(Plug p, const char *error_msg, int error_code, int calling_back) { }
|
||||
static void dummy_plug_receive(Plug p, int urgent, char *data, int len) { }
|
||||
static void dummy_plug_sent(Plug p, int bufsize) { }
|
||||
static int dummy_plug_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx) { return 1; }
|
||||
static const struct plug_function_table dummy_plug = {
|
||||
dummy_plug_log, dummy_plug_closing, dummy_plug_receive,
|
||||
dummy_plug_sent, dummy_plug_accepting
|
||||
};
|
||||
|
||||
struct X11FakeAuth *x11_invent_fake_auth(tree234 *authtree, int authtype)
|
||||
{
|
||||
struct X11FakeAuth *auth = snew(struct X11FakeAuth);
|
||||
@@ -306,8 +290,7 @@ struct X11Display *x11_setup_display(const char *display, Conf *conf)
|
||||
if (!err) {
|
||||
/* Create trial connection to see if there is a useful Unix-domain
|
||||
* socket */
|
||||
const struct plug_function_table *dummy = &dummy_plug;
|
||||
Socket s = sk_new(sk_addr_dup(ux), 0, 0, 0, 0, 0, (Plug)&dummy,
|
||||
Socket s = sk_new(sk_addr_dup(ux), 0, 0, 0, 0, 0, nullplug,
|
||||
#ifdef MPEXT
|
||||
0, 0
|
||||
#endif
|
||||
@@ -450,16 +433,37 @@ static const char *x11_verify(unsigned long peer_ip, int peer_port,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptrlen BinarySource_get_string_xauth(BinarySource *src)
|
||||
{
|
||||
size_t len = get_uint16(src);
|
||||
return get_data(src, len);
|
||||
}
|
||||
#define get_string_xauth(src) \
|
||||
BinarySource_get_string_xauth(BinarySource_UPCAST(src))
|
||||
|
||||
void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
const char *authfilename)
|
||||
{
|
||||
FILE *authfp;
|
||||
char *buf, *ptr, *str[4];
|
||||
int len[4];
|
||||
char *buf;
|
||||
int size;
|
||||
BinarySource src[1];
|
||||
int family, protocol;
|
||||
ptrlen addr, protoname, data;
|
||||
char *displaynum_string;
|
||||
int displaynum;
|
||||
int ideal_match = FALSE;
|
||||
char *ourhostname;
|
||||
|
||||
/* A maximally sized (wildly implausible) .Xauthority record
|
||||
* consists of a 16-bit integer to start with, then four strings,
|
||||
* each of which has a 16-bit length field followed by that many
|
||||
* bytes of data (i.e. up to 0xFFFF bytes). */
|
||||
const size_t MAX_RECORD_SIZE = 2 + 4 * (2+0xFFFF);
|
||||
|
||||
/* We'll want a buffer of twice that size (see below). */
|
||||
const size_t BUF_SIZE = 2 * MAX_RECORD_SIZE;
|
||||
|
||||
/*
|
||||
* Normally we should look for precisely the details specified in
|
||||
* `disp'. However, there's an oddity when the display is local:
|
||||
@@ -489,29 +493,41 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
|
||||
ourhostname = get_hostname();
|
||||
|
||||
/* Records in .Xauthority contain four strings of up to 64K each */
|
||||
buf = snewn(65537 * 4, char);
|
||||
/*
|
||||
* Allocate enough space to hold two maximally sized records, so
|
||||
* that a full record can start anywhere in the first half. That
|
||||
* way we avoid the accidentally-quadratic algorithm that would
|
||||
* arise if we moved everything to the front of the buffer after
|
||||
* consuming each record; instead, we only move everything to the
|
||||
* front after our current position gets past the half-way mark.
|
||||
* Before then, there's no need to move anyway; so this guarantees
|
||||
* linear time, in that every byte written into this buffer moves
|
||||
* at most once (because every move is from the second half of the
|
||||
* buffer to the first half).
|
||||
*/
|
||||
buf = snewn(BUF_SIZE, char);
|
||||
size = fread(buf, 1, BUF_SIZE, authfp);
|
||||
BinarySource_BARE_INIT(src, buf, size);
|
||||
|
||||
while (!ideal_match) {
|
||||
int c, i, j, match = FALSE;
|
||||
|
||||
#define GET do { c = fgetc(authfp); if (c == EOF) goto done; c = (unsigned char)c; } while (0)
|
||||
/* Expect a big-endian 2-byte number giving address family */
|
||||
GET; family = c;
|
||||
GET; family = (family << 8) | c;
|
||||
/* Then expect four strings, each composed of a big-endian 2-byte
|
||||
* length field followed by that many bytes of data */
|
||||
ptr = buf;
|
||||
for (i = 0; i < 4; i++) {
|
||||
GET; len[i] = c;
|
||||
GET; len[i] = (len[i] << 8) | c;
|
||||
str[i] = ptr;
|
||||
for (j = 0; j < len[i]; j++) {
|
||||
GET; *ptr++ = c;
|
||||
}
|
||||
*ptr++ = '\0';
|
||||
}
|
||||
#undef GET
|
||||
int match = FALSE;
|
||||
|
||||
if (src->pos >= MAX_RECORD_SIZE) {
|
||||
size -= src->pos;
|
||||
memcpy(buf, buf + src->pos, size);
|
||||
size += fread(buf + size, 1, BUF_SIZE - size, authfp);
|
||||
BinarySource_BARE_INIT(src, buf, size);
|
||||
}
|
||||
|
||||
family = get_uint16(src);
|
||||
addr = get_string_xauth(src);
|
||||
displaynum_string = mkstr(get_string_xauth(src));
|
||||
displaynum = atoi(displaynum_string);
|
||||
sfree(displaynum_string);
|
||||
protoname = get_string_xauth(src);
|
||||
data = get_string_xauth(src);
|
||||
if (get_err(src))
|
||||
break;
|
||||
|
||||
/*
|
||||
* Now we have a full X authority record in memory. See
|
||||
@@ -525,7 +541,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
* connect to the display. 0 means IPv4; 6 means IPv6;
|
||||
* 256 means Unix-domain sockets.
|
||||
*
|
||||
* - str[0] is the network address itself. For IPv4 and
|
||||
* - 'addr' is the network address itself. For IPv4 and
|
||||
* IPv6, this is a string of binary data of the
|
||||
* appropriate length (respectively 4 and 16 bytes)
|
||||
* representing the address in big-endian format, e.g.
|
||||
@@ -536,24 +552,23 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
* authority entries for Unix-domain displays on
|
||||
* several machines without them clashing).
|
||||
*
|
||||
* - str[1] is the display number. I've no idea why
|
||||
* - 'displaynum' is the display number. I've no idea why
|
||||
* .Xauthority stores this as a string when it has a
|
||||
* perfectly good integer format, but there we go.
|
||||
*
|
||||
* - str[2] is the authorisation method, encoded as its
|
||||
* canonical string name (i.e. "MIT-MAGIC-COOKIE-1",
|
||||
* "XDM-AUTHORIZATION-1" or something we don't
|
||||
* recognise).
|
||||
* - 'protoname' is the authorisation protocol, encoded as
|
||||
* its canonical string name (i.e. "MIT-MAGIC-COOKIE-1",
|
||||
* "XDM-AUTHORIZATION-1" or something we don't recognise).
|
||||
*
|
||||
* - str[3] is the actual authorisation data, stored in
|
||||
* - 'data' is the actual authorisation data, stored in
|
||||
* binary form.
|
||||
*/
|
||||
|
||||
if (disp->displaynum < 0 || disp->displaynum != atoi(str[1]))
|
||||
if (disp->displaynum < 0 || disp->displaynum != displaynum)
|
||||
continue; /* not the one */
|
||||
|
||||
for (protocol = 1; protocol < lenof(x11_authnames); protocol++)
|
||||
if (!strcmp(str[2], x11_authnames[protocol]))
|
||||
if (ptrlen_eq_string(protoname, x11_authnames[protocol]))
|
||||
break;
|
||||
if (protocol == lenof(x11_authnames))
|
||||
continue; /* don't recognise this protocol, look for another */
|
||||
@@ -564,7 +579,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
sk_addrtype(disp->addr) == ADDRTYPE_IPV4) {
|
||||
char buf[4];
|
||||
sk_addrcopy(disp->addr, buf);
|
||||
if (len[0] == 4 && !memcmp(str[0], buf, 4)) {
|
||||
if (addr.len == 4 && !memcmp(addr.ptr, buf, 4)) {
|
||||
match = TRUE;
|
||||
/* If this is a "localhost" entry, note it down
|
||||
* but carry on looking for a Unix-domain entry. */
|
||||
@@ -577,7 +592,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
sk_addrtype(disp->addr) == ADDRTYPE_IPV6) {
|
||||
char buf[16];
|
||||
sk_addrcopy(disp->addr, buf);
|
||||
if (len[0] == 16 && !memcmp(str[0], buf, 16)) {
|
||||
if (addr.len == 16 && !memcmp(addr.ptr, buf, 16)) {
|
||||
match = TRUE;
|
||||
ideal_match = !localhost;
|
||||
}
|
||||
@@ -585,7 +600,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
break;
|
||||
case 256: /* Unix-domain / localhost */
|
||||
if ((disp->unixdomain || localhost)
|
||||
&& ourhostname && !strcmp(ourhostname, str[0]))
|
||||
&& ourhostname && ptrlen_eq_string(addr, ourhostname))
|
||||
/* A matching Unix-domain socket is always the best
|
||||
* match. */
|
||||
match = ideal_match = TRUE;
|
||||
@@ -596,15 +611,14 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||
/* Current best guess -- may be overridden if !ideal_match */
|
||||
disp->localauthproto = protocol;
|
||||
sfree(disp->localauthdata); /* free previous guess, if any */
|
||||
disp->localauthdata = snewn(len[3], unsigned char);
|
||||
memcpy(disp->localauthdata, str[3], len[3]);
|
||||
disp->localauthdatalen = len[3];
|
||||
disp->localauthdata = snewn(data.len, unsigned char);
|
||||
memcpy(disp->localauthdata, data.ptr, data.len);
|
||||
disp->localauthdatalen = data.len;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
fclose(authfp);
|
||||
smemclr(buf, 65537 * 4);
|
||||
smemclr(buf, 2 * MAX_RECORD_SIZE);
|
||||
sfree(buf);
|
||||
sfree(ourhostname);
|
||||
}
|
||||
@@ -621,7 +635,8 @@ static void x11_send_init_error(struct X11Connection *conn,
|
||||
static void x11_closing(Plug plug, const char *error_msg, int error_code,
|
||||
int calling_back)
|
||||
{
|
||||
struct X11Connection *xconn = (struct X11Connection *) plug;
|
||||
struct X11Connection *xconn = FROMFIELD(
|
||||
plug, struct X11Connection, plugvt);
|
||||
|
||||
if (error_msg) {
|
||||
/*
|
||||
@@ -652,7 +667,8 @@ static void x11_closing(Plug plug, const char *error_msg, int error_code,
|
||||
|
||||
static void x11_receive(Plug plug, int urgent, char *data, int len)
|
||||
{
|
||||
struct X11Connection *xconn = (struct X11Connection *) plug;
|
||||
struct X11Connection *xconn = FROMFIELD(
|
||||
plug, struct X11Connection, plugvt);
|
||||
|
||||
if (sshfwd_write(xconn->c, data, len) > 0) {
|
||||
xconn->throttled = 1;
|
||||
@@ -663,7 +679,8 @@ static void x11_receive(Plug plug, int urgent, char *data, int len)
|
||||
|
||||
static void x11_sent(Plug plug, int bufsize)
|
||||
{
|
||||
struct X11Connection *xconn = (struct X11Connection *) plug;
|
||||
struct X11Connection *xconn = FROMFIELD(
|
||||
plug, struct X11Connection, plugvt);
|
||||
|
||||
sshfwd_unthrottle(xconn->c, bufsize);
|
||||
}
|
||||
@@ -686,6 +703,14 @@ int x11_get_screen_number(char *display)
|
||||
return atoi(display + n + 1);
|
||||
}
|
||||
|
||||
static const Plug_vtable X11Connection_plugvt = {
|
||||
x11_log,
|
||||
x11_closing,
|
||||
x11_receive,
|
||||
x11_sent,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Called to set up the X11Connection structure, though this does not
|
||||
* yet connect to an actual server.
|
||||
@@ -693,21 +718,13 @@ int x11_get_screen_number(char *display)
|
||||
struct X11Connection *x11_init(tree234 *authtree, void *c,
|
||||
const char *peeraddr, int peerport)
|
||||
{
|
||||
static const struct plug_function_table fn_table = {
|
||||
x11_log,
|
||||
x11_closing,
|
||||
x11_receive,
|
||||
x11_sent,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct X11Connection *xconn;
|
||||
|
||||
/*
|
||||
* Open socket.
|
||||
*/
|
||||
xconn = snew(struct X11Connection);
|
||||
xconn->fn = &fn_table;
|
||||
xconn->plugvt = &X11Connection_plugvt;
|
||||
xconn->auth_protocol = NULL;
|
||||
xconn->authtree = authtree;
|
||||
xconn->verified = 0;
|
||||
@@ -791,7 +808,7 @@ static void x11_send_init_error(struct X11Connection *xconn,
|
||||
PUT_16BIT(xconn->firstpkt[0], reply + 6, msgsize >> 2);/* data len */
|
||||
memset(reply + 8, 0, msgsize);
|
||||
memcpy(reply + 8, full_message, msglen);
|
||||
sshfwd_write(xconn->c, (char *)reply, 8 + msgsize);
|
||||
sshfwd_write(xconn->c, reply, 8 + msgsize);
|
||||
sshfwd_write_eof(xconn->c);
|
||||
xconn->no_data_sent_to_x_client = FALSE;
|
||||
sfree(reply);
|
||||
@@ -818,8 +835,10 @@ static int x11_parse_ip(const char *addr_string, unsigned long *ip)
|
||||
/*
|
||||
* Called to send data down the raw connection.
|
||||
*/
|
||||
int x11_send(struct X11Connection *xconn, char *data, int len)
|
||||
int x11_send(struct X11Connection *xconn, const void *vdata, int len)
|
||||
{
|
||||
const char *data = (const char *)vdata;
|
||||
|
||||
if (!xconn)
|
||||
return 0;
|
||||
|
||||
@@ -918,7 +937,7 @@ int x11_send(struct X11Connection *xconn, char *data, int len)
|
||||
xconn->disp = auth_matched->disp;
|
||||
xconn->s = new_connection(sk_addr_dup(xconn->disp->addr),
|
||||
xconn->disp->realhost, xconn->disp->port,
|
||||
0, 1, 0, 0, (Plug) xconn,
|
||||
0, 1, 0, 0, &xconn->plugvt,
|
||||
sshfwd_get_conf(xconn->c));
|
||||
if ((err = sk_socket_error(xconn->s)) != NULL) {
|
||||
char *err_message = dupprintf("unable to connect to"
|
||||
@@ -994,29 +1013,29 @@ void x11_send_eof(struct X11Connection *xconn)
|
||||
* representations of an X11 auth protocol name + hex cookie into our
|
||||
* usual integer protocol id and binary auth data.
|
||||
*/
|
||||
int x11_identify_auth_proto(const char *protoname)
|
||||
int x11_identify_auth_proto(ptrlen protoname)
|
||||
{
|
||||
int protocol;
|
||||
|
||||
for (protocol = 1; protocol < lenof(x11_authnames); protocol++)
|
||||
if (!strcmp(protoname, x11_authnames[protocol]))
|
||||
if (ptrlen_eq_string(protoname, x11_authnames[protocol]))
|
||||
return protocol;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *x11_dehexify(const char *hex, int *outlen)
|
||||
void *x11_dehexify(ptrlen hexpl, int *outlen)
|
||||
{
|
||||
int len, i;
|
||||
unsigned char *ret;
|
||||
|
||||
len = strlen(hex) / 2;
|
||||
len = hexpl.len / 2;
|
||||
ret = snewn(len, unsigned char);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
char bytestr[3];
|
||||
unsigned val = 0;
|
||||
bytestr[0] = hex[2*i];
|
||||
bytestr[1] = hex[2*i+1];
|
||||
bytestr[0] = ((const char *)hexpl.ptr)[2*i];
|
||||
bytestr[1] = ((const char *)hexpl.ptr)[2*i+1];
|
||||
bytestr[2] = '\0';
|
||||
sscanf(bytestr, "%x", &val);
|
||||
ret[i] = val;
|
||||
@@ -1065,8 +1084,7 @@ void *x11_make_greeting(int endian, int protomajor, int protominor,
|
||||
t = time(NULL);
|
||||
PUT_32BIT_MSB_FIRST(realauthdata+14, t);
|
||||
|
||||
des_encrypt_xdmauth((const unsigned char *)auth_data + 9,
|
||||
realauthdata, authdatalen);
|
||||
des_encrypt_xdmauth((char *)auth_data + 9, realauthdata, authdatalen);
|
||||
} else {
|
||||
authdata = realauthdata;
|
||||
authdatalen = 0;
|
||||
|
||||
Reference in New Issue
Block a user