1
0
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:
Martin Prikryl
2019-03-25 15:33:12 +00:00
71 changed files with 11408 additions and 9190 deletions

View File

@@ -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>

View File

@@ -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()

View File

@@ -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();

View File

@@ -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

View File

@@ -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);
//---------------------------------------------------------------------------

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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
View File

@@ -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
View File

@@ -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
View 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 */

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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
View 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
View 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
View File

@@ -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
View File

@@ -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);
/*

View File

@@ -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
View 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;

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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,

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

505
source/putty/ssh.h vendored
View File

@@ -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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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)
{
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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
View File

@@ -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
View 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
View File

@@ -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
View 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
View File

@@ -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
View File

@@ -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
View File

@@ -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

File diff suppressed because it is too large Load Diff

23
source/putty/sshgss.h vendored
View File

@@ -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
View File

@@ -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;
}

View File

@@ -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
View File

@@ -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

File diff suppressed because it is too large Load Diff

547
source/putty/sshrsa.c vendored
View File

@@ -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[] = {

View File

@@ -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 */

View File

@@ -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
View File

@@ -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 */

File diff suppressed because it is too large Load Diff

214
source/putty/sshzlib.c vendored
View File

@@ -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)"
};

View File

@@ -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

View File

@@ -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", &regkey)
== 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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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
View File

@@ -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;