diff --git a/contrib/win32/openssh/libssh.vcxproj b/contrib/win32/openssh/libssh.vcxproj
index 49889c4..061950b 100644
--- a/contrib/win32/openssh/libssh.vcxproj
+++ b/contrib/win32/openssh/libssh.vcxproj
@@ -258,6 +258,13 @@
+
+
+ true
+
+
+
+
diff --git a/contrib/win32/openssh/libssh.vcxproj.filters b/contrib/win32/openssh/libssh.vcxproj.filters
index 730bc3d..87cba0c 100644
--- a/contrib/win32/openssh/libssh.vcxproj.filters
+++ b/contrib/win32/openssh/libssh.vcxproj.filters
@@ -288,5 +288,16 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
\ No newline at end of file
diff --git a/contrib/win32/openssh/win32compat.vcxproj b/contrib/win32/openssh/win32compat.vcxproj
index 11ac11a..874ec42 100644
--- a/contrib/win32/openssh/win32compat.vcxproj
+++ b/contrib/win32/openssh/win32compat.vcxproj
@@ -159,11 +159,13 @@
-
-
-
-
-
+
+ true
+ true
+ true
+ true
+
+
diff --git a/contrib/win32/openssh/win32compat.vcxproj.filters b/contrib/win32/openssh/win32compat.vcxproj.filters
index 6b28eaa..9f07cc8 100644
--- a/contrib/win32/openssh/win32compat.vcxproj.filters
+++ b/contrib/win32/openssh/win32compat.vcxproj.filters
@@ -81,19 +81,10 @@
Source Files
-
+
Source Files
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
+
Source Files
@@ -140,7 +131,10 @@
Header Files
-
+
+ Header Files
+
+
Header Files
diff --git a/contrib/win32/win32compat/cng_dh.c b/contrib/win32/win32compat/cng_dh.c
new file mode 100644
index 0000000..b2ecab9
--- /dev/null
+++ b/contrib/win32/win32compat/cng_dh.c
@@ -0,0 +1,324 @@
+
+#include
+#include
+#include
+#include
+#include
+#include "crypto-wrap.h"
+
+
+// CNG Diffie-hellman Kex context
+typedef struct cng_dh_ctx {
+ int size;
+ PBYTE g;
+ PBYTE p;
+ PBYTE pub;
+ BCRYPT_KEY_HANDLE hPrivate;
+ BCRYPT_ALG_HANDLE hAlg;
+} CNG_DH_CTX;
+
+
+struct sshdh {
+ CNG_DH_CTX *dh;
+};
+
+
+//function to reverse the order of a byte array
+static void
+cng_dh_swap_bytes(void *pv, size_t n)
+{
+ char *p = (char*)pv;
+ size_t lo, hi;
+ for (lo = 0, hi = n - 1; hi>lo; lo++, hi--)
+ {
+ char tmp = p[lo];
+ p[lo] = p[hi];
+ p[hi] = tmp;
+ }
+}
+
+
+/* DH wrappers */
+
+struct sshdh *
+ sshdh_new(void)
+{
+ return (struct sshdh *)(malloc(sizeof(struct sshdh)));
+}
+
+void
+sshdh_free(struct sshdh *dh)
+{
+ if (dh != NULL) {
+ if (dh->dh != NULL)
+ {
+ CNG_DH_CTX * pCtx = (CNG_DH_CTX*)dh->dh;
+
+ if (pCtx->hAlg)
+ BCryptCloseAlgorithmProvider(pCtx->hAlg, 0);
+
+ if (pCtx->hPrivate)
+ BCryptDestroyKey(pCtx->hPrivate);
+
+ ZeroMemory(pCtx, sizeof(*pCtx));
+ free(pCtx);
+ }
+ free(dh);
+ }
+}
+
+struct sshbn *
+ sshdh_pubkey(struct sshdh *dh)
+{
+ CNG_DH_CTX *pCtx = dh->dh;
+ struct sshbn * bn = NULL;
+
+ sshbn_from(pCtx->pub, pCtx->size, &bn);
+ return bn;
+
+}
+
+struct sshbn *
+ sshdh_p(struct sshdh *dh)
+{
+ CNG_DH_CTX *pCtx = dh->dh;
+ struct sshbn * bn = NULL;
+
+ sshbn_from(pCtx->p, pCtx->size, &bn);
+
+ return bn;
+}
+
+struct sshbn *
+ sshdh_g(struct sshdh *dh)
+{
+ CNG_DH_CTX *pCtx = dh->dh;
+ struct sshbn * bn = NULL;
+
+ sshbn_from(pCtx->g, pCtx->size, &bn);
+
+ return bn;
+}
+
+void
+sshdh_dump(struct sshdh *dh)
+{
+ return;
+}
+
+// XXX needed?
+size_t
+sshdh_shared_key_size(struct sshdh *dh)
+{
+ int sz;
+ CNG_DH_CTX *pCtx = dh->dh;
+
+ if (dh == NULL || dh->dh == NULL || (sz = pCtx->size) < 0)
+ return 0;
+ return (size_t)sz;
+}
+
+// import a bignum public key
+static BCRYPT_KEY_HANDLE
+cng_dh_set_remote_pub_key2(struct sshdh *dh, struct sshbn *b)
+{
+ BCRYPT_KEY_HANDLE hPub = NULL;
+ CNG_DH_CTX *pCtx = dh->dh;
+
+ if (sshbn_bytes(b) > pCtx->size)
+ return NULL;
+
+ DWORD cbBlob = sizeof(BCRYPT_DH_KEY_BLOB) + (pCtx->size * 3);
+
+ PBYTE pBlob = (PBYTE)malloc(cbBlob);
+
+ BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
+ pKeyBlob->cbKey = pCtx->size;
+ pKeyBlob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
+ PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
+ PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
+ PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
+
+ memcpy(pModulus, pCtx->p, pCtx->size);
+ memcpy(pGenerator, pCtx->g, pCtx->size);
+ memset(pPublic, 0, pCtx->size);
+
+ sshbn_to(b, pPublic + pCtx->size - (sshbn_bytes(b)));
+
+
+ HRESULT Status = 0;
+
+ if (S_OK != (Status = BCryptImportKeyPair(pCtx->hAlg, NULL, BCRYPT_DH_PUBLIC_BLOB, &hPub, pBlob, cbBlob, 0)))
+ goto cleanup;
+
+cleanup:
+ if (pBlob) free(pBlob);
+
+ return hPub;
+}
+
+
+int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey,
+struct sshbn **shared_secretp)
+{
+ HRESULT hr = S_OK;
+ CNG_DH_CTX *pCtx = dh->dh;
+ PBYTE pSecret = (PBYTE)malloc(pCtx->size);
+ DWORD pSecret_len = pCtx->size;
+ DWORD size = pCtx->size;
+ struct sshbn * bn = NULL;
+ BCRYPT_SECRET_HANDLE hSecret;
+
+ BCRYPT_KEY_HANDLE hRemotePub = cng_dh_set_remote_pub_key2(dh, pubkey);
+ if (hRemotePub != NULL)
+ {
+
+ if (S_OK == (hr = BCryptSecretAgreement(pCtx->hPrivate, hRemotePub, &hSecret, 0)))
+ {
+
+ hr = BCryptDeriveKey(hSecret, L"TRUNCATE", NULL, pSecret, pSecret_len, &size, 0);
+ if (S_OK == hr)
+ {
+ cng_dh_swap_bytes(pSecret, size);
+
+ sshbn_from(pSecret, size, &bn);
+ memset(pSecret, 0, size);
+ free(pSecret);
+ *shared_secretp = bn;
+ }
+ BCryptDestroySecret(hSecret);
+ }
+ }
+ return S_OK==hr?0:-1;
+}
+
+
+
+
+int
+sshdh_generate(struct sshdh *dh, size_t len)
+{
+ HRESULT Status;
+ BCRYPT_DH_PARAMETER_HEADER *DhParamHdrPointer = NULL;
+ DWORD DhParamBlobLength = 0;
+ PBYTE DhParamBlob = NULL;
+ BCRYPT_ALG_HANDLE hAlg = NULL;
+ PBYTE pBlob = NULL;
+ BCRYPT_KEY_HANDLE hPriv = NULL;
+ CNG_DH_CTX *pCtx = dh->dh;
+ DWORD cbBlob = 0;
+
+
+ DhParamBlobLength = sizeof(BCRYPT_DH_PARAMETER_HEADER) + (pCtx->size * 2);
+
+ if (NULL == (DhParamBlob = (PBYTE)malloc(DhParamBlobLength)))
+ return -1;
+
+ DhParamHdrPointer = (BCRYPT_DH_PARAMETER_HEADER *)DhParamBlob;
+ DhParamHdrPointer->cbLength = DhParamBlobLength;
+ DhParamHdrPointer->cbKeyLength = pCtx->size;
+ DhParamHdrPointer->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC;
+
+ memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER), pCtx->p, pCtx->size);
+ memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER) + pCtx->size, pCtx->g, pCtx->size);
+
+ if (S_OK != (Status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_DH_ALGORITHM, NULL, 0)))
+ goto error;
+
+
+ if (S_OK != (Status = BCryptGenerateKeyPair(hAlg, &hPriv, pCtx->size*8, 0)))
+ goto error;
+
+
+ if (S_OK != (Status = BCryptSetProperty(hPriv, BCRYPT_DH_PARAMETERS, DhParamBlob, DhParamBlobLength, 0)))
+ goto error;
+
+ if (S_OK != (Status = BCryptFinalizeKeyPair(hPriv, 0)))
+ goto error;
+
+ if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &cbBlob, 0)))
+ goto error;
+
+ if (NULL == (pBlob = (PBYTE)malloc(cbBlob)))
+ {
+ Status = STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, pBlob, cbBlob, &cbBlob, 0)))
+ goto error;
+
+
+
+ BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
+ PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
+ PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
+ PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
+
+ pCtx->hAlg = hAlg;
+ pCtx->hPrivate = hPriv;
+ memcpy(pCtx->pub, pPublic, pCtx->size);
+
+ return 0;
+error:
+
+ return -1;
+}
+
+int
+sshdh_new_group_hex(const char *gen, const char *modulus, struct sshdh **dhp)
+{
+ struct sshdh *ret;
+ struct sshbn * g = NULL;
+ struct sshbn * p = NULL;
+
+ sshbn_from_hex(gen, &g);
+ sshbn_from_hex(modulus, &p);
+ *dhp = NULL;
+
+ ret = sshdh_new_group(g, p);
+
+ if (g != NULL)
+ sshbn_free(g);
+ if (p != NULL)
+ sshbn_free(p);
+
+ *dhp = ret;
+
+ return 0;
+}
+
+
+
+/* XXX transfers ownership of gen, modulus */
+struct sshdh *
+ sshdh_new_group(struct sshbn *gen, struct sshbn *modulus)
+{
+ struct sshdh *dh;
+
+ PBYTE pBlob = NULL;
+ DWORD keysize = sshbn_bytes(modulus);
+ DWORD cbBlob = 0;
+
+ dh = sshdh_new();
+
+ pBlob = (PBYTE)malloc(sizeof(CNG_DH_CTX) + (3 * keysize));
+ memset(pBlob, 0, sizeof(CNG_DH_CTX) + (3 * keysize));
+
+ CNG_DH_CTX * pCtx = (CNG_DH_CTX *)pBlob;
+
+ pCtx->size = keysize;
+ pCtx->p = pBlob + sizeof(CNG_DH_CTX);
+ pCtx->g = pCtx->p + keysize;
+ pCtx->pub = pCtx->g + keysize;
+
+ sshbn_to(gen, pCtx->g + keysize - sshbn_bytes(gen));
+ sshbn_to(modulus, pCtx->p + keysize - sshbn_bytes(modulus));
+
+ dh->dh = pCtx;
+ return dh;
+}
+
+
+
+
diff --git a/contrib/win32/win32compat/cng_kex.c b/contrib/win32/win32compat/cng_kex.c
deleted file mode 100644
index 6661455..0000000
--- a/contrib/win32/win32compat/cng_kex.c
+++ /dev/null
@@ -1,471 +0,0 @@
-
-#include
-#include
-
-typedef struct dh_st DH;
-
-char *strdelim(char **);
-char *strsep(char **stringp, const char *delim);
-// Prime in big-endian format. (Group 2 prime from RFC 2409)
-static
-const
-BYTE OakleyGroup2P[] =
-{
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F,
- 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B,
- 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67,
- 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
- 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95,
- 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
- 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51,
- 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
- 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF,
- 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB,
- 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B,
- 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-// Generator in big-endian format. (Group 2 generator from RFC 2409)
-static
-const
-BYTE OakleyGroup2G[] =
-{
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
-};
-
-
-// Prime in big-endian format. (Group 14 prime from RFC 3526)
-static
-const
-BYTE OakleyGroup14P[] =
-{
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
- 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
- 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
- 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
- 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
- 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
- 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
- 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
- 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
- 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
- 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-// Generator in big-endian format. (Group 14 generator from RFC 3526)
-static
-const
-BYTE OakleyGroup14G[] =
-{
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-};
-
-
-
-DH *
-cng_dh_new_group_asc(const char *gen, const char *modulus)
-{
-
- DH *dh;
- BIGNUM * p = NULL;
- BIGNUM * g = NULL;
-
- if (BN_hex2bn(&p, modulus) == 0 ||
- BN_hex2bn(&g, gen) == 0) {
- return NULL;
- }
- dh = cng_dh_new_group(g, p);
- BN_free(p);
- BN_free(g);
- return dh;
-
-}
-
-
-
-int cng_kex_supported(void)
-{
- return IsWindows8Point1OrGreater() == FALSE ? 0 : 1;
-}
-
-DH * cng_setup_group1(void)
-{
- PBYTE pBlob = NULL;
- DWORD keysize = sizeof(OakleyGroup2P);
- DWORD cbBlob = 0;
-
- pBlob = (PBYTE)malloc(sizeof(CNG_DH_CTX) + (3 * keysize));
- memset(pBlob, 0, sizeof(CNG_DH_CTX) + (3 * keysize));
-
- CNG_DH_CTX * pCtx = (CNG_DH_CTX *)pBlob;
-
- pCtx->size = keysize;
- pCtx->p = pBlob + sizeof(CNG_DH_CTX);
- pCtx->g = pCtx->p + keysize;
- pCtx->pub = pCtx->g + keysize;
-
- memcpy(pCtx->p, OakleyGroup2P, sizeof(OakleyGroup2P));
- memcpy(pCtx->g, OakleyGroup2G, sizeof(OakleyGroup2G));
-
- return (DH *)pCtx;
-}
-
-DH * cng_setup_group14(void)
-{
- PBYTE pBlob = NULL;
- DWORD keysize = sizeof(OakleyGroup14P);
- DWORD cbBlob = 0;
-
- pBlob = (PBYTE)malloc(sizeof(CNG_DH_CTX) + (3 * keysize));
- memset(pBlob, 0, sizeof(CNG_DH_CTX) + (3 * keysize));
-
- CNG_DH_CTX * pCtx = (CNG_DH_CTX *)pBlob;
-
- pCtx->size = keysize;
- pCtx->p = pBlob + sizeof(CNG_DH_CTX);
- pCtx->g = pCtx->p + keysize;
- pCtx->pub = pCtx->g + keysize;
-
- memcpy(pCtx->p, OakleyGroup14P, sizeof(OakleyGroup14P));
- memcpy(pCtx->g, OakleyGroup14G, sizeof(OakleyGroup14G));
-
- return (DH *)pCtx;
-}
-
-
-
-//function to reverse the order of a byte array
-static void
-cng_dh_swap_bytes(void *pv, size_t n)
-{
- char *p = (char*)pv;
- size_t lo, hi;
- for (lo = 0, hi = n - 1; hi>lo; lo++, hi--)
- {
- char tmp = p[lo];
- p[lo] = p[hi];
- p[hi] = tmp;
- }
-}
-
-
-// import a bignum public key
-BCRYPT_KEY_HANDLE
-cng_dh_set_remote_pub_key(DH * dh, BIGNUM * b)
-{
- BCRYPT_KEY_HANDLE hPub = NULL;
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)dh;
-
- if (BN_num_bytes(b) > pCtx->size)
- return NULL;
-
- DWORD cbBlob = sizeof(BCRYPT_DH_KEY_BLOB) + (pCtx->size * 3);
-
- PBYTE pBlob = (PBYTE)malloc(cbBlob);
-
- BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
- pKeyBlob->cbKey = pCtx->size;
- pKeyBlob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
- PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
- PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
- PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
-
- memcpy(pModulus, pCtx->p, pCtx->size);
- memcpy(pGenerator, pCtx->g, pCtx->size);
- memset(pPublic, 0, pCtx->size);
-
- BN_bn2bin(b, pPublic + pCtx->size - BN_num_bytes(b));
-
-
- HRESULT Status = 0;
-
- if (S_OK != (Status = BCryptImportKeyPair(pCtx->hAlg, NULL, BCRYPT_DH_PUBLIC_BLOB, &hPub, pBlob, cbBlob, 0)))
- goto cleanup;
-
-cleanup:
- if (pBlob) free(pBlob);
-
- return hPub;
-}
-
-
-// generate KEX private/public keys for this side
-int
-cng_dh_gen_key(DH *dh, int need)
-{
- HRESULT Status;
- BCRYPT_DH_PARAMETER_HEADER *DhParamHdrPointer = NULL;
- DWORD DhParamBlobLength = 0;
- PBYTE DhParamBlob = NULL;
- BCRYPT_ALG_HANDLE hAlg = NULL;
- PBYTE pBlob = NULL;
- BCRYPT_KEY_HANDLE hPriv = NULL;
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)dh;
- DWORD cbBlob = 0;
-
-
- DhParamBlobLength = sizeof(BCRYPT_DH_PARAMETER_HEADER) + (pCtx->size * 2);
-
- if (NULL == (DhParamBlob = (PBYTE)malloc(DhParamBlobLength)))
- return -1;
-
- DhParamHdrPointer = (BCRYPT_DH_PARAMETER_HEADER *)DhParamBlob;
- DhParamHdrPointer->cbLength = DhParamBlobLength;
- DhParamHdrPointer->cbKeyLength = pCtx->size;
- DhParamHdrPointer->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC;
-
- memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER), pCtx->p, pCtx->size);
- memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER) + pCtx->size, pCtx->g, pCtx->size);
-
- if (S_OK != (Status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_DH_ALGORITHM, NULL, 0)))
- goto error;
-
-
- if (S_OK != (Status = BCryptGenerateKeyPair(hAlg, &hPriv, pCtx->size * 8, 0)))
- goto error;
-
-
- if (S_OK != (Status = BCryptSetProperty(hPriv, BCRYPT_DH_PARAMETERS, DhParamBlob, DhParamBlobLength, 0)))
- goto error;
-
- if (S_OK != (Status = BCryptFinalizeKeyPair(hPriv, 0)))
- goto error;
-
- if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &cbBlob, 0)))
- goto error;
-
- if (NULL == (pBlob = (PBYTE)malloc(cbBlob)))
- {
- Status = STATUS_NO_MEMORY;
- goto error;
- }
-
- if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, pBlob, cbBlob, &cbBlob, 0)))
- goto error;
-
-
-
- BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
- PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
- PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
- PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
-
- pCtx->hAlg = hAlg;
- pCtx->hPrivate = hPriv;
- memcpy(pCtx->pub, pPublic, pCtx->size);
-
- return 0;
-error:
-
- return -1;
-}
-
-
-
-BIGNUM *
-cng_dh_export_secret(DH * dh, BCRYPT_SECRET_HANDLE hSecret)
-{
- HRESULT hr = S_OK;
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)dh;
- PBYTE pSecret = (PBYTE)malloc(pCtx->size);
- DWORD pSecret_len = pCtx->size;
- DWORD size = pCtx->size;
- BIGNUM * bn = NULL;
-
- hr = BCryptDeriveKey(hSecret, L"TRUNCATE", NULL, pSecret, pSecret_len, &size, 0);
- if (S_OK == hr)
- {
- cng_dh_swap_bytes(pSecret, size);
- bn = BN_bin2bn(pSecret, size, NULL);
- memset(pSecret, 0, size);
- free(pSecret);
- }
- return bn;
-}
-
-// calculate and return secret as a bignum
-BIGNUM *
-cng_dh_get_secret(DH * dh, BIGNUM * remote_pub)
-{
- HRESULT hr = S_OK;
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)dh;
- PBYTE pSecret = (PBYTE)malloc(pCtx->size);
- DWORD pSecret_len = pCtx->size;
- DWORD size = pCtx->size;
- BIGNUM * bn = NULL;
- BCRYPT_SECRET_HANDLE hSecret;
-
- BCRYPT_KEY_HANDLE hRemotePub = cng_dh_set_remote_pub_key(dh, remote_pub);
- if (hRemotePub != NULL)
- {
-
- if (S_OK == (hr = BCryptSecretAgreement(pCtx->hPrivate, hRemotePub, &hSecret, 0)))
- {
-
- hr = BCryptDeriveKey(hSecret, L"TRUNCATE", NULL, pSecret, pSecret_len, &size, 0);
- if (S_OK == hr)
- {
- cng_dh_swap_bytes(pSecret, size);
- bn = BN_bin2bn(pSecret, size, NULL);
- memset(pSecret, 0, size);
- free(pSecret);
- }
- BCryptDestroySecret(hSecret);
- }
- }
- return bn;
-}
-
-
-// return our public key as a bignum (for sending to the other side)
-BIGNUM *
-cng_dh_get_local_pub_key(DH * dh)
-{
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)dh;
- BIGNUM * bn = NULL;
-
- bn = BN_bin2bn(pCtx->pub, pCtx->size, NULL);
-
- return bn;
-}
-
-BIGNUM *
-cng_dh_get_p(DH * dh)
-{
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)dh;
- BIGNUM * bn = NULL;
-
- bn = BN_bin2bn(pCtx->p, pCtx->size, NULL);
- return bn;
-}
-
-BIGNUM *
-cng_dh_get_g(DH * dh)
-{
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)dh;
- BIGNUM * bn = NULL;
-
- bn = BN_bin2bn(pCtx->g, pCtx->size, NULL);
- return bn;
-}
-
-
-
-int
-cng_dh_pub_is_valid(DH * dh, BIGNUM *dh_pub)
-{
- int i;
- int n = BN_num_bits(dh_pub);
- int bits_set = 0;
- BIGNUM *tmp;
- BIGNUM *p = cng_dh_get_p(dh);
-
- if (NULL == p) {
- logit("invalid DH prime value");
- return 0;
- }
-
-
- if (dh_pub->neg) {
- logit("invalid public DH value: negative");
- return 0;
- }
- if (BN_cmp(dh_pub, BN_value_one()) != 1) { /* pub_exp <= 1 */
- logit("invalid public DH value: <= 1");
- return 0;
- }
-
- if ((tmp = BN_new()) == NULL) {
- error("%s: BN_new failed", __FUNCTION__);
- return 0;
- }
- if (!BN_sub(tmp, p, BN_value_one()) ||
- BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
- BN_clear_free(tmp);
- logit("invalid public DH value: >= p-1");
- return 0;
- }
- BN_clear_free(tmp);
-
- for (i = 0; i <= n; i++)
- if (BN_is_bit_set(dh_pub, i))
- bits_set++;
- debug2("bits set: %d/%d", bits_set, BN_num_bits(p));
-
- /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
- if (bits_set > 1)
- {
- BN_clear_free(p);
- return 1;
- }
-
- logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(p));
- BN_clear_free(p);
- return 0;
-}
-
-
-DH *
-cng_dh_new_group(BIGNUM *gen, BIGNUM *modulus)
-{
-
- PBYTE pBlob = NULL;
- DWORD keysize = BN_num_bytes(modulus);;
- DWORD cbBlob = 0;
-
-
- pBlob = (PBYTE)malloc(sizeof(CNG_DH_CTX) + (3 * keysize));
- memset(pBlob, 0, sizeof(CNG_DH_CTX) + (3 * keysize));
-
- CNG_DH_CTX * pCtx = (CNG_DH_CTX *)pBlob;
-
- pCtx->size = keysize;
- pCtx->p = pBlob + sizeof(CNG_DH_CTX);
- pCtx->g = pCtx->p + keysize;
- pCtx->pub = pCtx->g + keysize;
-
- BN_bn2bin(gen, pCtx->g + keysize - BN_num_bytes(gen));
- BN_bn2bin(modulus, pCtx->p + keysize - BN_num_bytes(modulus));
-
- return (DH *)pCtx;
-}
-
-
-
-void cng_dh_free_context(DH * dh)
-{
- CNG_DH_CTX * pCtx = (CNG_DH_CTX*)dh;
-
- if (pCtx->hAlg)
- BCryptCloseAlgorithmProvider(pCtx->hAlg, 0);
-
- if (pCtx->hPrivate)
- BCryptDestroyKey(pCtx->hPrivate);
-
- free(pCtx);
-
-}
-
diff --git a/contrib/win32/win32compat/cng_kex.h b/contrib/win32/win32compat/cng_kex.h
deleted file mode 100644
index 1b97239..0000000
--- a/contrib/win32/win32compat/cng_kex.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-#include
-// CNG Diffie-hellman Kex context
-typedef struct cng_dh_ctx {
- int size;
- PBYTE g;
- PBYTE p;
- PBYTE pub;
- BCRYPT_KEY_HANDLE hPrivate;
- BCRYPT_ALG_HANDLE hAlg;
-} CNG_DH_CTX;
-
-
-DH * cng_setup_group1(void);
-DH * cng_setup_group14(void);
-DH * cng_dh_new_group(BIGNUM *gen, BIGNUM *modulus);
-BCRYPT_KEY_HANDLE cng_dh_set_remote_pub_key(DH *pCtx, BIGNUM * b);
-int cng_dh_gen_key(DH *dh, int need);
-BIGNUM * cng_dh_get_secret(DH * pCtx, BIGNUM * remote_pub);
-BIGNUM * cng_dh_get_local_pub_key(DH * dh);
-BIGNUM * cng_dh_get_p(DH * dh);
-BIGNUM * cng_dh_get_g(DH * dh);
-int cng_dh_pub_is_valid(DH * dh, BIGNUM *dh_pub);
-void cng_dh_swap_bytes(void *pv, size_t n);
-int cng_kex_supported(void);
-DH * cng_dh_new_group_asc(const char *gen, const char *modulus);
-void cng_dh_free_context(DH * dh);
diff --git a/contrib/win32/win32compat/cng_kexdhc.c b/contrib/win32/win32compat/cng_kexdhc.c
deleted file mode 100644
index b3ef54e..0000000
--- a/contrib/win32/win32compat/cng_kexdhc.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-* cng implementation of Diffie-Hellman Key Exchange for Oakley groups 2 and 14 (ssh group1 and group14)
-*
-*/
-
-#include "includes.h"
-
-
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-
-#include "sshkey.h"
-#include "cipher.h"
-#include "digest.h"
-#include "kex.h"
-#include "log.h"
-#include "packet.h"
-#include "dh.h"
-#include "ssh2.h"
-#include "dispatch.h"
-#include "compat.h"
-#include "ssherr.h"
-#include "sshbuf.h"
-
-#include
-#include
-
-
-
-
-static int cng_input_kex_dh(int, u_int32_t, void *);
-
-int
-cng_kexdh_client(struct ssh *ssh)
-{
-
- // switch to standard openssl version if not supported
- if (!cng_kex_supported())
- return kexdh_client(ssh);
-
-
- struct kex *kex = ssh->kex;
- int r;
- BIGNUM * pub_key;
- /* generate and send 'e', client DH public key */
- switch (kex->kex_type) {
- case KEX_DH_GRP1_SHA1:
- kex->dh = cng_setup_group1();
- break;
- case KEX_DH_GRP14_SHA1:
- kex->dh = cng_setup_group14();
- break;
- default:
- r = SSH_ERR_INVALID_ARGUMENT;
- goto out;
- }
- if (kex->dh == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- debug("sending SSH2_MSG_KEXDH_INIT");
- if ((r = cng_dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
- (pub_key = cng_dh_get_local_pub_key(kex->dh)) == 0 ||
- (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
- goto out;
-#ifdef DEBUG_KEXDH
- DHparams_print_fp(stderr, kex->dh);
- fprintf(stderr, "pub= ");
- BN_print_fp(stderr, kex->dh->pub_key);
- fprintf(stderr, "\n");
-#endif
- debug("expecting SSH2_MSG_KEXDH_REPLY");
- ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &cng_input_kex_dh);
- r = 0;
-out:
- if (pub_key)
- BN_free(pub_key);
- return r;
-}
-
-static int
-cng_input_kex_dh(int type, u_int32_t seq, void *ctxt)
-{
- struct ssh *ssh = ctxt;
- struct kex *kex = ssh->kex;
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)kex->dh;
- BIGNUM *dh_server_pub = NULL, *shared_secret = NULL,*dh_local_pub=NULL;
- struct sshkey *server_host_key = NULL;
- u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL;
- u_char hash[SSH_DIGEST_MAX_LENGTH];
- size_t klen = 0, slen, sbloblen, hashlen;
- int kout, r;
-
- if (kex->verify_host_key == NULL) {
- r = SSH_ERR_INVALID_ARGUMENT;
- goto out;
- }
- /* key, cert */
- if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
- &sbloblen)) != 0 ||
- (r = sshkey_from_blob(server_host_key_blob, sbloblen,
- &server_host_key)) != 0)
- goto out;
- if (server_host_key->type != kex->hostkey_type ||
- (kex->hostkey_type == KEY_ECDSA &&
- server_host_key->ecdsa_nid != kex->hostkey_nid)) {
- r = SSH_ERR_KEY_TYPE_MISMATCH;
- goto out;
- }
- if (kex->verify_host_key(server_host_key, ssh) == -1) {
- r = SSH_ERR_SIGNATURE_INVALID;
- goto out;
- }
- /* DH parameter f, server public DH key */
- if ((dh_server_pub = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- /* signed H */
- if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
- (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
- goto out;
-
- if (!cng_dh_pub_is_valid(kex->dh, dh_server_pub)) {
- sshpkt_disconnect(ssh, "bad server public DH value");
- r = SSH_ERR_MESSAGE_INCOMPLETE;
- goto out;
- }
-
- shared_secret = cng_dh_get_secret(kex->dh, dh_server_pub);
- if (shared_secret == NULL)
- goto out;
-
- dh_local_pub = cng_dh_get_local_pub_key(kex->dh);
-
- /* calc and verify H */
- hashlen = sizeof(hash);
- if ((r = kex_dh_hash(
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- server_host_key_blob, sbloblen,
- dh_local_pub,
- dh_server_pub,
- shared_secret,
- hash, &hashlen)) != 0)
- goto out;
-
- if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
- ssh->compat)) != 0)
- goto out;
-
- /* save session id */
- if (kex->session_id == NULL) {
- kex->session_id_len = hashlen;
- kex->session_id = malloc(kex->session_id_len);
- if (kex->session_id == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- memcpy(kex->session_id, hash, kex->session_id_len);
- }
-
- if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
- r = kex_send_newkeys(ssh);
-out:
- explicit_bzero(hash, sizeof(hash));
- cng_dh_free_context(kex->dh);
- kex->dh = NULL;
- if (dh_server_pub)
- BN_clear_free(dh_server_pub);
- if (dh_local_pub)
- BN_clear_free(dh_local_pub);
- if (kbuf) {
- explicit_bzero(kbuf, klen);
- free(kbuf);
- }
- if (shared_secret)
- BN_clear_free(shared_secret);
- sshkey_free(server_host_key);
- free(server_host_key_blob);
- free(signature);
- return r;
-}
-
diff --git a/contrib/win32/win32compat/cng_kexdhs.c b/contrib/win32/win32compat/cng_kexdhs.c
deleted file mode 100644
index 7a1a035..0000000
--- a/contrib/win32/win32compat/cng_kexdhs.c
+++ /dev/null
@@ -1,198 +0,0 @@
-
-#include "includes.h"
-
-#ifdef WIN32_FIXME
-#undef GSSAPI
-#undef KRB5
-#endif
-
-#ifdef WITH_OPENSSL
-
-#include
-
-#include
-#include
-#include
-
-#include
-
-#include "sshkey.h"
-#include "cipher.h"
-#include "digest.h"
-#include "kex.h"
-#include "log.h"
-#include "packet.h"
-#include "dh.h"
-#include "ssh2.h"
-
-#include "dispatch.h"
-#include "compat.h"
-#include "ssherr.h"
-#include "sshbuf.h"
-#include
-#include
-
-
-static int cng_input_kex_dh_init(int, u_int32_t, void *);
-
-int
-cng_kexdh_server(struct ssh *ssh)
-{
- if (!cng_kex_supported())
- return kexdh_server(ssh);
-
-
- struct kex *kex = ssh->kex;
- int r;
-
- /* generate server DH public key */
- switch (kex->kex_type) {
- case KEX_DH_GRP1_SHA1:
- kex->dh = cng_setup_group1();
- break;
- case KEX_DH_GRP14_SHA1:
- kex->dh = cng_setup_group14();
- break;
- default:
- r = SSH_ERR_INVALID_ARGUMENT;
- goto out;
- }
- if (kex->dh == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if ((r = cng_dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
- goto out;
-
- debug("expecting SSH2_MSG_KEXDH_INIT");
- ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &cng_input_kex_dh_init);
- r = 0;
-out:
- return r;
-}
-
-int
-cng_input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
-{
- struct ssh *ssh = ctxt;
- struct kex *kex = ssh->kex;
- BIGNUM *shared_secret = NULL, *dh_client_pub = NULL, *dh_local_pub = NULL;
- struct sshkey *server_host_public, *server_host_private;
- u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
- u_char hash[SSH_DIGEST_MAX_LENGTH];
- size_t sbloblen, slen;
- size_t klen = 0, hashlen;
- int kout, r;
-
- if (kex->load_host_public_key == NULL ||
- kex->load_host_private_key == NULL) {
- r = SSH_ERR_INVALID_ARGUMENT;
- goto out;
- }
- server_host_public = kex->load_host_public_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
- server_host_private = kex->load_host_private_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
- if (server_host_public == NULL) {
- r = SSH_ERR_NO_HOSTKEY_LOADED;
- goto out;
- }
-
- /* key, cert */
- if ((dh_client_pub = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
- goto out;
-
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "dh_client_pub= ");
- BN_print_fp(stderr, dh_client_pub);
- fprintf(stderr, "\n");
- debug("bits %d", BN_num_bits(dh_client_pub));
-#endif
-
-#ifdef DEBUG_KEXDH
- DHparams_print_fp(stderr, kex->dh);
- fprintf(stderr, "pub= ");
- BN_print_fp(stderr, kex->dh->pub_key);
- fprintf(stderr, "\n");
-#endif
- if (!cng_dh_pub_is_valid(kex->dh, dh_client_pub)) {
- sshpkt_disconnect(ssh, "bad client public DH value");
- r = SSH_ERR_MESSAGE_INCOMPLETE;
- goto out;
- }
-
- shared_secret = cng_dh_get_secret(kex->dh, dh_client_pub);
- if (shared_secret == NULL)
- goto out;
-
-#ifdef DEBUG_KEXDH
- dump_digest("shared secret", kbuf, kout);
-#endif
- if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
- &sbloblen)) != 0)
- goto out;
-
- dh_local_pub = cng_dh_get_local_pub_key(kex->dh);
-
- /* calc H */
- hashlen = sizeof(hash);
- if ((r = kex_dh_hash(
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- server_host_key_blob, sbloblen,
- dh_client_pub,
- dh_local_pub,
- shared_secret,
- hash, &hashlen)) != 0)
- goto out;
-
- /* save session id := H */
- if (kex->session_id == NULL) {
- kex->session_id_len = hashlen;
- kex->session_id = malloc(kex->session_id_len);
- if (kex->session_id == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- memcpy(kex->session_id, hash, kex->session_id_len);
- }
-
- /* sign H */
- if ((r = kex->sign(server_host_private, server_host_public,
- &signature, &slen, hash, hashlen, ssh->compat)) < 0)
- goto out;
-
- /* destroy_sensitive_data(); */
-
- /* send server hostkey, DH pubkey 'f' and singed H */
- if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 ||
- (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, dh_local_pub)) != 0 || /* f */
- (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
- goto out;
-
- if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
- r = kex_send_newkeys(ssh);
-out:
- explicit_bzero(hash, sizeof(hash));
- cng_dh_free_context(kex->dh);
- kex->dh = NULL;
- if (dh_client_pub)
- BN_clear_free(dh_client_pub);
- if (dh_local_pub)
- BN_clear_free(dh_local_pub);
- if (shared_secret)
- BN_clear_free(shared_secret);
- free(server_host_key_blob);
- free(signature);
- return r;
-}
-#endif /* WITH_OPENSSL */
diff --git a/contrib/win32/win32compat/cng_kexgexc.c b/contrib/win32/win32compat/cng_kexgexc.c
deleted file mode 100644
index a99ac62..0000000
--- a/contrib/win32/win32compat/cng_kexgexc.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/* $OpenBSD: kexgexc.c,v 1.22 2015/05/26 23:23:40 dtucker Exp $ */
-/*
-* Copyright (c) 2000 Niels Provos. All rights reserved.
-* Copyright (c) 2001 Markus Friedl. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions
-* are met:
-* 1. Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* 2. Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-*
-* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "includes.h"
-
-#ifdef WITH_OPENSSL
-
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-
-#include "sshkey.h"
-#include "cipher.h"
-#include "digest.h"
-#include "kex.h"
-#include "log.h"
-#include "packet.h"
-#include "dh.h"
-#include "ssh2.h"
-#include "compat.h"
-#include "dispatch.h"
-#include "ssherr.h"
-#include "sshbuf.h"
-#include
-#include
-
-static int cng_input_kex_dh_gex_group(int, u_int32_t, void *);
-static int cng_input_kex_dh_gex_reply(int, u_int32_t, void *);
-
-int
-cng_kexgex_client(struct ssh *ssh)
-{
- // switch to standard openssl version if not supported
- if (!cng_kex_supported())
- return kexgex_client(ssh);
-
- struct kex *kex = ssh->kex;
- int r;
- u_int nbits;
-
- nbits = dh_estimate(kex->dh_need * 8);
-
- kex->min = DH_GRP_MIN;
- kex->max = DH_GRP_MAX;
- kex->nbits = nbits;
- if (datafellows & SSH_BUG_DHGEX_LARGE)
- kex->nbits = MIN(kex->nbits, 4096);
- /* New GEX request */
- if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 ||
- (r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
- (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
- (r = sshpkt_put_u32(ssh, kex->max)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
- goto out;
- debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent",
- kex->min, kex->nbits, kex->max);
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
- kex->min, kex->nbits, kex->max);
-#endif
- ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP,
- &cng_input_kex_dh_gex_group);
- r = 0;
-out:
- return r;
-}
-
-static int
-cng_input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
-{
- struct ssh *ssh = ctxt;
- struct kex *kex = ssh->kex;
- BIGNUM *p = NULL, *g = NULL;
- int r, bits;
- BIGNUM * pub_key = NULL;
-
- debug("got SSH2_MSG_KEX_DH_GEX_GROUP");
-
- if ((p = BN_new()) == NULL ||
- (g = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if ((r = sshpkt_get_bignum2(ssh, p)) != 0 ||
- (r = sshpkt_get_bignum2(ssh, g)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
- goto out;
- if ((bits = BN_num_bits(p)) < 0 ||
- (u_int)bits < kex->min || (u_int)bits > kex->max) {
- r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
- goto out;
- }
- if ((kex->dh = cng_dh_new_group(g, p)) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- p = g = NULL; /* belong to kex->dh now */
-
- /* generate and send 'e', client DH public key */
- if ((r = cng_dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
- (pub_key = cng_dh_get_local_pub_key(kex->dh)) == 0 ||
- (r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
- goto out;
- debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
-#ifdef DEBUG_KEXDH
- DHparams_print_fp(stderr, kex->dh);
- fprintf(stderr, "pub= ");
- BN_print_fp(stderr, kex->dh->pub_key);
- fprintf(stderr, "\n");
-#endif
- ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL);
- ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &cng_input_kex_dh_gex_reply);
- r = 0;
-out:
- if (p)
- BN_clear_free(p);
- if (g)
- BN_clear_free(g);
- return r;
-}
-
-static int
-cng_input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
-{
- struct ssh *ssh = ctxt;
- struct kex *kex = ssh->kex;
- CNG_DH_CTX *pCtx = (CNG_DH_CTX *)kex->dh;
- BIGNUM *dh_server_pub = NULL, *shared_secret = NULL,*dh_local_pub = NULL,*p = NULL,*g = NULL;
- struct sshkey *server_host_key = NULL;
- u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
- u_char hash[SSH_DIGEST_MAX_LENGTH];
- size_t klen = 0, slen, sbloblen, hashlen;
- int kout, r;
-
- debug("got SSH2_MSG_KEX_DH_GEX_REPLY");
- if (kex->verify_host_key == NULL) {
- r = SSH_ERR_INVALID_ARGUMENT;
- goto out;
- }
- /* key, cert */
- if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
- &sbloblen)) != 0 ||
- (r = sshkey_from_blob(server_host_key_blob, sbloblen,
- &server_host_key)) != 0)
- goto out;
- if (server_host_key->type != kex->hostkey_type) {
- r = SSH_ERR_KEY_TYPE_MISMATCH;
- goto out;
- }
- if (server_host_key->type != kex->hostkey_type ||
- (kex->hostkey_type == KEY_ECDSA &&
- server_host_key->ecdsa_nid != kex->hostkey_nid)) {
- r = SSH_ERR_KEY_TYPE_MISMATCH;
- goto out;
- }
- if (kex->verify_host_key(server_host_key, ssh) == -1) {
- r = SSH_ERR_SIGNATURE_INVALID;
- goto out;
- }
- /* DH parameter f, server public DH key */
- if ((dh_server_pub = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- /* signed H */
- if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
- (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
- goto out;
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "dh_server_pub= ");
- BN_print_fp(stderr, dh_server_pub);
- fprintf(stderr, "\n");
- debug("bits %d", BN_num_bits(dh_server_pub));
-#endif
- if (!cng_dh_pub_is_valid(kex->dh, dh_server_pub)) {
- sshpkt_disconnect(ssh, "bad server public DH value");
- r = SSH_ERR_MESSAGE_INCOMPLETE;
- goto out;
- }
-
- shared_secret = cng_dh_get_secret(kex->dh, dh_server_pub);
- if (shared_secret == NULL)
- goto out;
-
- if (ssh->compat & SSH_OLD_DHGEX)
- kex->min = kex->max = -1;
-
- dh_local_pub = cng_dh_get_local_pub_key(kex->dh);
- p = cng_dh_get_p(kex->dh);
- g = cng_dh_get_g(kex->dh);
-
-
-
- /* calc and verify H */
- hashlen = sizeof(hash);
- if ((r = kexgex_hash(
- kex->hash_alg,
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- server_host_key_blob, sbloblen,
- kex->min, kex->nbits, kex->max,
- p, g,
- dh_local_pub,
- dh_server_pub,
- shared_secret,
- hash, &hashlen)) != 0)
- goto out;
-
- if ((r = sshkey_verify(server_host_key, signature, slen, hash,
- hashlen, ssh->compat)) != 0)
- goto out;
-
- /* save session id */
- if (kex->session_id == NULL) {
- kex->session_id_len = hashlen;
- kex->session_id = malloc(kex->session_id_len);
- if (kex->session_id == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- memcpy(kex->session_id, hash, kex->session_id_len);
- }
-
- if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
- r = kex_send_newkeys(ssh);
-out:
- explicit_bzero(hash, sizeof(hash));
- cng_dh_free_context(kex->dh);
- kex->dh = NULL;
- if (dh_server_pub)
- BN_clear_free(dh_server_pub);
- if (dh_local_pub)
- BN_clear_free(dh_local_pub);
- if (p)
- BN_clear_free(p);
- if (g)
- BN_clear_free(g);
- if (kbuf) {
- explicit_bzero(kbuf, klen);
- free(kbuf);
- }
- if (shared_secret)
- BN_clear_free(shared_secret);
- sshkey_free(server_host_key);
- free(server_host_key_blob);
- free(signature);
- return r;
-}
-#endif /* WITH_OPENSSL */
diff --git a/contrib/win32/win32compat/cng_kexgexs.c b/contrib/win32/win32compat/cng_kexgexs.c
deleted file mode 100644
index de44859..0000000
--- a/contrib/win32/win32compat/cng_kexgexs.c
+++ /dev/null
@@ -1,283 +0,0 @@
-
-#include "includes.h"
-
-#ifdef WIN32_FIXME
-#undef GSSAPI
-#undef KRB5
-#endif
-
-#ifdef WITH_OPENSSL
-
-#include /* MIN MAX */
-
-#include
-#include
-#include
-#include
-
-#include
-
-#include "sshkey.h"
-#include "cipher.h"
-#include "digest.h"
-#include "kex.h"
-#include "log.h"
-#include "packet.h"
-#include "dh.h"
-#include "ssh2.h"
-#include "compat.h"
-#include "monitor_wrap.h"
-#include "dispatch.h"
-#include "ssherr.h"
-#include "sshbuf.h"
-#include
-#include
-
-static int cng_input_kex_dh_gex_request(int, u_int32_t, void *);
-static int cng_input_kex_dh_gex_init(int, u_int32_t, void *);
-
-/*
- let openssl do the choosing of the group. Once it has, we
- can grab the group parameters and create a cng dh context.
-*/
-static
-DH * cng_context_from_dh(DH * dh)
-{
- DH *pCtx = NULL;
-
- pCtx = cng_dh_new_group(dh->g, dh->p);
-
- return (DH *)pCtx;
-}
-
-
-/*
-let openssl do the choosing of the group. Once it has, we
-can grab the group parameters and create a cng dh context.
-*/
-static DH *
-cng_choose_dh(int min, int wantbits, int max)
-{
- DH *pCtx = NULL;
-
- DH * dh = choose_dh(min, wantbits, max);
- if (dh != NULL)
- {
- pCtx = cng_context_from_dh(dh);
-
- DH_free(dh);
- }
- return (DH *)pCtx;
-}
-
-
-int
-cng_kexgex_server(struct ssh *ssh)
-{
- if (!cng_kex_supported())
- return kexgex_server(ssh);
-
- ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST,
- &cng_input_kex_dh_gex_request);
- debug("expecting SSH2_MSG_KEX_DH_GEX_REQUEST");
- return 0;
-}
-
-static int
-cng_input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
-{
- struct ssh *ssh = ctxt;
- struct kex *kex = ssh->kex;
- int r;
- u_int min = 0, max = 0, nbits = 0;
- BIGNUM * p = NULL;;
- BIGNUM * g = NULL;
-
-
- debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
- if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
- (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
- (r = sshpkt_get_u32(ssh, &max)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
- goto out;
- kex->nbits = nbits;
- kex->min = min;
- kex->max = max;
- min = MAX(DH_GRP_MIN, min);
- max = MIN(DH_GRP_MAX, max);
- nbits = MAX(DH_GRP_MIN, nbits);
- nbits = MIN(DH_GRP_MAX, nbits);
-
- if (kex->max < kex->min || kex->nbits < kex->min ||
- kex->max < kex->nbits) {
- r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
- goto out;
- }
-
- /* Contact privileged parent */
- kex->dh = cng_choose_dh(min, nbits, max);
- if (kex->dh == NULL) {
- sshpkt_disconnect(ssh, "no matching DH grp found");
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
-
- p = cng_dh_get_p(kex->dh);
- g = cng_dh_get_g(kex->dh);
- debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
- if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 ||
- (r = sshpkt_put_bignum2(ssh,p )) != 0 ||
- (r = sshpkt_put_bignum2(ssh, g)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
- goto out;
-
- /* Compute our exchange value in parallel with the client */
- if ((r = cng_dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
- goto out;
-
- debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
- ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &cng_input_kex_dh_gex_init);
- r = 0;
-out:
- if (p != NULL)
- BN_free(p);
- if (g != NULL)
- BN_free(g);
- return r;
-}
-
-static int
-cng_input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
-{
- struct ssh *ssh = ctxt;
- struct kex *kex = ssh->kex;
- BIGNUM *shared_secret = NULL, *dh_client_pub = NULL, *dh_local_pub=NULL, *p=NULL, *g=NULL;
- struct sshkey *server_host_public, *server_host_private;
- u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
- u_char hash[SSH_DIGEST_MAX_LENGTH];
- size_t sbloblen, slen;
- size_t klen = 0, hashlen;
- int kout, r;
-
- if (kex->load_host_public_key == NULL ||
- kex->load_host_private_key == NULL) {
- r = SSH_ERR_INVALID_ARGUMENT;
- goto out;
- }
- server_host_public = kex->load_host_public_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
- server_host_private = kex->load_host_private_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
- if (server_host_public == NULL) {
- r = SSH_ERR_NO_HOSTKEY_LOADED;
- goto out;
- }
-
- /* key, cert */
- if ((dh_client_pub = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
- goto out;
-
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "dh_client_pub= ");
- BN_print_fp(stderr, dh_client_pub);
- fprintf(stderr, "\n");
- debug("bits %d", BN_num_bits(dh_client_pub));
-#endif
-
-#ifdef DEBUG_KEXDH
- DHparams_print_fp(stderr, kex->dh);
- fprintf(stderr, "pub= ");
- BN_print_fp(stderr, kex->dh->pub_key);
- fprintf(stderr, "\n");
-#endif
- if (!cng_dh_pub_is_valid(kex->dh, dh_client_pub)) {
- sshpkt_disconnect(ssh, "bad client public DH value");
- r = SSH_ERR_MESSAGE_INCOMPLETE;
- goto out;
- }
-
- shared_secret = cng_dh_get_secret(kex->dh, dh_client_pub);
- if (shared_secret == NULL)
- goto out;
-#ifdef DEBUG_KEXDH
- dump_digest("shared secret", kbuf, kout);
-#endif
- if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
- &sbloblen)) != 0)
- goto out;
-
- p = cng_dh_get_p(kex->dh);
- g = cng_dh_get_g(kex->dh);
- dh_local_pub = cng_dh_get_local_pub_key(kex->dh);
- /* calc H */
- hashlen = sizeof(hash);
- if ((r = kexgex_hash(
- kex->hash_alg,
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- server_host_key_blob, sbloblen,
- kex->min, kex->nbits, kex->max,
- p, g,
- dh_client_pub,
- dh_local_pub,
- shared_secret,
- hash, &hashlen)) != 0)
- goto out;
-
- /* save session id := H */
- if (kex->session_id == NULL) {
- kex->session_id_len = hashlen;
- kex->session_id = malloc(kex->session_id_len);
- if (kex->session_id == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- memcpy(kex->session_id, hash, kex->session_id_len);
- }
-
- /* sign H */
- if ((r = kex->sign(server_host_private, server_host_public,
- &signature, &slen, hash, hashlen, ssh->compat)) < 0)
- goto out;
-
-
-
- /* send server hostkey, DH pubkey 'f' and singed H */
- if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 ||
- (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, dh_local_pub)) != 0 || /* f */
- (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
- goto out;
-
- if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
- r = kex_send_newkeys(ssh);
-out:
- cng_dh_free_context(kex->dh);
- kex->dh = NULL;
- if (dh_client_pub)
- BN_clear_free(dh_client_pub);
- if (dh_local_pub)
- BN_clear_free(dh_local_pub);
- if (p)
- BN_clear_free(p);
- if (g)
- BN_clear_free(g);
- if (kbuf) {
- explicit_bzero(kbuf, klen);
- free(kbuf);
- }
- if (shared_secret)
- BN_clear_free(shared_secret);
- free(server_host_key_blob);
- free(signature);
- return r;
-}
-#endif /* WITH_OPENSSL */
diff --git a/contrib/win32/win32compat/cng_openssl_dh.c b/contrib/win32/win32compat/cng_openssl_dh.c
new file mode 100644
index 0000000..97b90a4
--- /dev/null
+++ b/contrib/win32/win32compat/cng_openssl_dh.c
@@ -0,0 +1,487 @@
+
+#include
+
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "sshbuf.h"
+#include "packet.h"
+#include "ssherr.h"
+#include
+#include "crypto-wrap.h"
+#include
+
+
+// CNG Diffie-hellman Kex context
+typedef struct cng_dh_ctx {
+ int size;
+ PBYTE g;
+ PBYTE p;
+ PBYTE pub;
+ BCRYPT_KEY_HANDLE hPrivate;
+ BCRYPT_ALG_HANDLE hAlg;
+} CNG_DH_CTX;
+
+
+struct sshdh {
+ void *dh;
+};
+
+struct sshbn {
+ BIGNUM *bn;
+};
+
+
+int cng_supported(void)
+{
+ return (IsWindows8Point1OrGreater());
+}
+
+//function to reverse the order of a byte array
+static void
+cng_dh_swap_bytes(void *pv, size_t n)
+{
+ char *p = (char*)pv;
+ size_t lo, hi;
+ for (lo = 0, hi = n - 1; hi>lo; lo++, hi--)
+ {
+ char tmp = p[lo];
+ p[lo] = p[hi];
+ p[hi] = tmp;
+ }
+}
+
+
+static struct sshbn *
+bnwrap(BIGNUM *bn)
+{
+ struct sshbn *ret;
+
+ if (bn == NULL)
+ return NULL;
+
+ if ((ret = calloc(1, sizeof(*ret))) == NULL)
+ return NULL;
+ if ((ret->bn = BN_dup(bn)) == NULL) {
+ free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+
+/* DH wrappers */
+
+struct sshdh *
+ sshdh_new(void)
+{
+ if (!cng_supported())
+ {
+ struct sshdh *ret;
+
+ if ((ret = calloc(1, sizeof(*ret))) == NULL)
+ return NULL;
+ if ((ret->dh = DH_new()) == NULL) {
+ free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+ return (struct sshdh *)(malloc(sizeof(struct sshdh)));
+}
+
+void
+sshdh_free(struct sshdh *dh)
+{
+ if (!cng_supported())
+ {
+ if (dh != NULL) {
+ if (dh->dh != NULL)
+ DH_free(dh->dh);
+ explicit_bzero(dh, sizeof(*dh));
+ free(dh);
+ }
+ return;
+ }
+
+ if (dh != NULL) {
+ if (dh->dh != NULL)
+ {
+ CNG_DH_CTX * pCtx = (CNG_DH_CTX*)dh->dh;
+
+ if (pCtx->hAlg)
+ BCryptCloseAlgorithmProvider(pCtx->hAlg, 0);
+
+ if (pCtx->hPrivate)
+ BCryptDestroyKey(pCtx->hPrivate);
+
+ ZeroMemory(pCtx, sizeof(*pCtx));
+ free(pCtx);
+ }
+ free(dh);
+ }
+}
+
+struct sshbn *
+ sshdh_pubkey(struct sshdh *dh)
+{
+ if (!cng_supported())
+ {
+ return bnwrap(((DH *)(dh->dh))->pub_key);
+ }
+
+ CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
+ struct sshbn * bn = NULL;
+
+ sshbn_from(pCtx->pub, pCtx->size, &bn);
+ return bn;
+
+}
+
+struct sshbn *
+ sshdh_p(struct sshdh *dh)
+{
+ if (!cng_supported())
+ {
+ return bnwrap(((DH *)(dh->dh))->p);
+ }
+
+ CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
+ struct sshbn * bn = NULL;
+
+ sshbn_from(pCtx->p, pCtx->size, &bn);
+
+ return bn;
+}
+
+struct sshbn *
+ sshdh_g(struct sshdh *dh)
+{
+ if (!cng_supported())
+ {
+ return bnwrap(((DH *)(dh->dh))->g);
+ }
+
+ CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
+ struct sshbn * bn = NULL;
+
+ sshbn_from(pCtx->g, pCtx->size, &bn);
+
+ return bn;
+}
+
+void
+sshdh_dump(struct sshdh *dh)
+{
+ if (!cng_supported())
+ {
+ DHparams_print_fp(stderr, dh->dh);
+ fprintf(stderr, "pub= ");
+ BN_print_fp(stderr, ((DH*)(dh->dh))->pub_key);
+ fprintf(stderr, "\n");
+ }
+ return;
+}
+
+// XXX needed?
+size_t
+sshdh_shared_key_size(struct sshdh *dh)
+{
+ if (!cng_supported())
+ {
+ int sz;
+
+ if (dh == NULL || dh->dh == NULL || (sz = DH_size(dh->dh)) < 0)
+ return 0;
+ return (size_t)sz;
+ }
+
+ int sz;
+ CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
+
+ if (dh == NULL || dh->dh == NULL || (sz = pCtx->size) < 0)
+ return 0;
+ return (size_t)sz;
+}
+
+// import a bignum public key
+static BCRYPT_KEY_HANDLE
+cng_dh_set_remote_pub_key2(struct sshdh *dh, struct sshbn *b)
+{
+
+ BCRYPT_KEY_HANDLE hPub = NULL;
+ CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
+
+ if (sshbn_bytes(b) > pCtx->size)
+ return NULL;
+
+ DWORD cbBlob = sizeof(BCRYPT_DH_KEY_BLOB) + (pCtx->size * 3);
+
+ PBYTE pBlob = (PBYTE)malloc(cbBlob);
+
+ BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
+ pKeyBlob->cbKey = pCtx->size;
+ pKeyBlob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
+ PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
+ PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
+ PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
+
+ memcpy(pModulus, pCtx->p, pCtx->size);
+ memcpy(pGenerator, pCtx->g, pCtx->size);
+ memset(pPublic, 0, pCtx->size);
+
+ sshbn_to(b, pPublic + pCtx->size - (sshbn_bytes(b)));
+
+
+ HRESULT Status = 0;
+
+ if (S_OK != (Status = BCryptImportKeyPair(pCtx->hAlg, NULL, BCRYPT_DH_PUBLIC_BLOB, &hPub, pBlob, cbBlob, 0)))
+ goto cleanup;
+
+cleanup:
+ if (pBlob) free(pBlob);
+
+ return hPub;
+}
+
+
+int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey,
+struct sshbn **shared_secretp)
+{
+ if (!cng_supported())
+ {
+ u_char *sbuf;
+ int r, slen;
+
+ *shared_secretp = NULL;
+ if ((slen = DH_size(dh->dh)) <= 0)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((sbuf = calloc(1, slen)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = DH_compute_key(sbuf, pubkey->bn, dh->dh)) < 0 ||
+ r != slen) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if ((r = sshbn_from(sbuf, slen, shared_secretp)) != 0)
+ goto out;
+ /* success */
+ r = 0;
+ out:
+ explicit_bzero(sbuf, slen);
+ free(sbuf);
+ return r;
+ }
+
+ HRESULT hr = S_OK;
+ CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
+ PBYTE pSecret = (PBYTE)malloc(pCtx->size);
+ DWORD pSecret_len = pCtx->size;
+ DWORD size = pCtx->size;
+ struct sshbn * bn = NULL;
+ BCRYPT_SECRET_HANDLE hSecret;
+
+ BCRYPT_KEY_HANDLE hRemotePub = cng_dh_set_remote_pub_key2(dh, pubkey);
+ if (hRemotePub != NULL)
+ {
+
+ if (S_OK == (hr = BCryptSecretAgreement(pCtx->hPrivate, hRemotePub, &hSecret, 0)))
+ {
+
+ hr = BCryptDeriveKey(hSecret, L"TRUNCATE", NULL, pSecret, pSecret_len, &size, 0);
+ if (S_OK == hr)
+ {
+ cng_dh_swap_bytes(pSecret, size);
+
+ sshbn_from(pSecret, size, &bn);
+ memset(pSecret, 0, size);
+ free(pSecret);
+ *shared_secretp = bn;
+ }
+ BCryptDestroySecret(hSecret);
+ }
+ }
+ return S_OK == hr ? 0 : -1;
+}
+
+
+
+
+int
+sshdh_generate(struct sshdh *dh, size_t len)
+{
+ if (!cng_supported())
+ {
+ if (len > INT_MAX)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if (len != 0)
+ ((DH*)(dh->dh))->length = (int)len;
+ if (DH_generate_key(dh->dh) != 1)
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ return 0;
+ }
+
+ HRESULT Status;
+ BCRYPT_DH_PARAMETER_HEADER *DhParamHdrPointer = NULL;
+ DWORD DhParamBlobLength = 0;
+ PBYTE DhParamBlob = NULL;
+ BCRYPT_ALG_HANDLE hAlg = NULL;
+ PBYTE pBlob = NULL;
+ BCRYPT_KEY_HANDLE hPriv = NULL;
+ CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
+ DWORD cbBlob = 0;
+
+
+ DhParamBlobLength = sizeof(BCRYPT_DH_PARAMETER_HEADER) + (pCtx->size * 2);
+
+ if (NULL == (DhParamBlob = (PBYTE)malloc(DhParamBlobLength)))
+ return -1;
+
+ DhParamHdrPointer = (BCRYPT_DH_PARAMETER_HEADER *)DhParamBlob;
+ DhParamHdrPointer->cbLength = DhParamBlobLength;
+ DhParamHdrPointer->cbKeyLength = pCtx->size;
+ DhParamHdrPointer->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC;
+
+ memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER), pCtx->p, pCtx->size);
+ memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER) + pCtx->size, pCtx->g, pCtx->size);
+
+ if (S_OK != (Status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_DH_ALGORITHM, NULL, 0)))
+ goto error;
+
+
+ if (S_OK != (Status = BCryptGenerateKeyPair(hAlg, &hPriv, pCtx->size * 8, 0)))
+ goto error;
+
+
+ if (S_OK != (Status = BCryptSetProperty(hPriv, BCRYPT_DH_PARAMETERS, DhParamBlob, DhParamBlobLength, 0)))
+ goto error;
+
+ if (S_OK != (Status = BCryptFinalizeKeyPair(hPriv, 0)))
+ goto error;
+
+ if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &cbBlob, 0)))
+ goto error;
+
+ if (NULL == (pBlob = (PBYTE)malloc(cbBlob)))
+ {
+ Status = STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, pBlob, cbBlob, &cbBlob, 0)))
+ goto error;
+
+
+
+ BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
+ PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
+ PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
+ PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
+
+ pCtx->hAlg = hAlg;
+ pCtx->hPrivate = hPriv;
+ memcpy(pCtx->pub, pPublic, pCtx->size);
+
+ return 0;
+error:
+
+ return -1;
+}
+
+int
+sshdh_new_group_hex(const char *gen, const char *modulus, struct sshdh **dhp)
+{
+ if (!cng_supported())
+ {
+ struct sshdh *ret;
+
+ *dhp = NULL;
+ if ((ret = sshdh_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if (BN_hex2bn(&(((DH*)(ret->dh))->p), modulus) == 0 ||
+ BN_hex2bn(&(((DH*)(ret->dh))->g), gen) == 0) {
+ sshdh_free(ret);
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ }
+ *dhp = ret;
+ return 0;
+ }
+
+ struct sshdh *ret;
+ struct sshbn * g = NULL;
+ struct sshbn * p = NULL;
+
+ sshbn_from_hex(gen, &g);
+ sshbn_from_hex(modulus, &p);
+ *dhp = NULL;
+
+ ret = sshdh_new_group(g, p);
+
+ if (g != NULL)
+ sshbn_free(g);
+ if (p != NULL)
+ sshbn_free(p);
+
+ *dhp = ret;
+
+ return 0;
+}
+
+
+
+/* XXX transfers ownership of gen, modulus */
+struct sshdh *
+ sshdh_new_group(struct sshbn *gen, struct sshbn *modulus)
+{
+ if (!cng_supported())
+ {
+ struct sshdh *dh;
+
+ if ((dh = sshdh_new()) == NULL)
+ return NULL;
+ ((DH*)(dh->dh))->p = modulus->bn;
+ ((DH*)(dh->dh))->g = gen->bn;
+ modulus->bn = gen->bn = NULL;
+ sshbn_free(gen);
+ sshbn_free(modulus);
+ return (dh);
+
+ }
+
+ struct sshdh *dh;
+
+ PBYTE pBlob = NULL;
+ DWORD keysize = sshbn_bytes(modulus);
+ DWORD cbBlob = 0;
+
+ dh = sshdh_new();
+
+ pBlob = (PBYTE)malloc(sizeof(CNG_DH_CTX) + (3 * keysize));
+ memset(pBlob, 0, sizeof(CNG_DH_CTX) + (3 * keysize));
+
+ CNG_DH_CTX * pCtx = (CNG_DH_CTX *)pBlob;
+
+ pCtx->size = keysize;
+ pCtx->p = pBlob + sizeof(CNG_DH_CTX);
+ pCtx->g = pCtx->p + keysize;
+ pCtx->pub = pCtx->g + keysize;
+
+ sshbn_to(gen, pCtx->g + keysize - sshbn_bytes(gen));
+ sshbn_to(modulus, pCtx->p + keysize - sshbn_bytes(modulus));
+
+ dh->dh = (void *)pCtx;
+ return dh;
+}
+
+
+
+
diff --git a/crypto-wrap.h b/crypto-wrap.h
new file mode 100644
index 0000000..f1e4934
--- /dev/null
+++ b/crypto-wrap.h
@@ -0,0 +1,51 @@
+
+#ifndef _OPENSSL_WRAP_H
+#define _OPENSSL_WRAP_H
+
+struct sshdh;
+struct sshbn;
+struct sshbuf;
+struct ssh;
+
+struct sshdh *sshdh_new(void);
+void sshdh_free(struct sshdh *dh);
+struct sshbn *sshdh_pubkey(struct sshdh *dh);
+struct sshbn *sshdh_p(struct sshdh *dh);
+struct sshbn *sshdh_g(struct sshdh *dh);
+void sshdh_dump(struct sshdh *dh);
+size_t sshdh_shared_key_size(struct sshdh *dh);
+int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey,
+struct sshbn **shared_secretp);
+int sshdh_generate(struct sshdh *dh, size_t len);
+int sshdh_new_group_hex(const char *gen, const char *modulus,
+struct sshdh **dhp);
+struct sshdh *sshdh_new_group(struct sshbn *gen, struct sshbn *modulus);
+
+struct sshbn *sshbn_new(void);
+void sshbn_free(struct sshbn *bn);
+int sshbn_from(const void *d, size_t l, struct sshbn **retp);
+int sshbn_from_hex(const char *hex, struct sshbn **retp);
+size_t sshbn_bits(const struct sshbn *bn);
+const struct sshbn *sshbn_value_0(void);
+const struct sshbn *sshbn_value_1(void);
+int sshbn_cmp(const struct sshbn *a, const struct sshbn *b);
+int sshbn_sub(struct sshbn *r, const struct sshbn *a, const struct sshbn *b);
+int sshbn_is_bit_set(const struct sshbn *bn, size_t i);
+int sshbn_to(const struct sshbn *a, unsigned char *to);
+size_t sshbn_bytes(const struct sshbn *bn);
+
+/* XXX move to sshbuf.h; rename s/_wrap$// */
+int sshbuf_get_bignum2_wrap(struct sshbuf *buf, struct sshbn *bn);
+int sshbuf_get_bignum1_wrap(struct sshbuf *buf, struct sshbn *bn);
+int sshbuf_put_bignum2_wrap(struct sshbuf *buf, const struct sshbn *bn);
+int sshbuf_put_bignum1_wrap(struct sshbuf *buf, const struct sshbn *bn);
+int sshpkt_get_bignum2_wrap(struct ssh *ssh, struct sshbn *bn);
+int sshpkt_put_bignum2_wrap(struct ssh *ssh, const struct sshbn *bn);
+
+/* bridge to unwrapped OpenSSL APIs; XXX remove later */
+struct sshbn *sshbn_from_bignum(BIGNUM *bn);
+BIGNUM *sshbn_bignum(struct sshbn *bn);
+DH *sshdh_dh(struct sshdh *dh);
+
+
+#endif /* _OPENSSL_WRAP_H */
\ No newline at end of file
diff --git a/dh.c b/dh.c
index 4c639ac..1d2a3bc 100644
--- a/dh.c
+++ b/dh.c
@@ -41,6 +41,7 @@
#include "log.h"
#include "misc.h"
#include "ssherr.h"
+#include "crypto-wrap.h"
static int
parse_prime(int linenum, char *line, struct dhgroup *dhg)
@@ -49,6 +50,7 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
char *strsize, *gen, *prime;
const char *errstr = NULL;
long long n;
+ int r;
dhg->p = dhg->g = NULL;
cp = line;
@@ -109,53 +111,45 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
goto fail;
}
- if ((dhg->g = BN_new()) == NULL ||
- (dhg->p = BN_new()) == NULL) {
- error("parse_prime: BN_new failed");
+ if ((r = sshbn_from_hex(gen, &dhg->g)) != 0 ||
+ (r = sshbn_from_hex(prime, &dhg->p)) != 0)
+ {
goto fail;
}
- if (BN_hex2bn(&dhg->g, gen) == 0) {
- error("moduli:%d: could not parse generator value", linenum);
+ if (sshbn_bits(dhg->p) != dhg->size) {
+ error("moduli:%d: prime has wrong size: actual %zu listed %zu",
+ linenum, sshbn_bits(dhg->p), dhg->size - 1);
goto fail;
}
- if (BN_hex2bn(&dhg->p, prime) == 0) {
- error("moduli:%d: could not parse prime value", linenum);
- goto fail;
- }
- if (BN_num_bits(dhg->p) != dhg->size) {
- error("moduli:%d: prime has wrong size: actual %d listed %d",
- linenum, BN_num_bits(dhg->p), dhg->size - 1);
- goto fail;
- }
- if (BN_cmp(dhg->g, BN_value_one()) <= 0) {
+
+ if (sshbn_cmp(dhg->g, sshbn_value_1()) <= 0) {
error("moduli:%d: generator is invalid", linenum);
goto fail;
}
return 1;
fail:
- if (dhg->g != NULL)
- BN_clear_free(dhg->g);
- if (dhg->p != NULL)
- BN_clear_free(dhg->p);
+ sshbn_free(dhg->g);
+ sshbn_free(dhg->p);
dhg->g = dhg->p = NULL;
return 0;
}
-DH *
-choose_dh(int min, int wantbits, int max)
+struct sshdh *
+choose_dh(u_int min, u_int wantbits, u_int max)
{
FILE *f;
char line[4096];
- int best, bestcount, which;
- int linenum;
+ u_int best, bestcount, which, linenum;
+ int r;
struct dhgroup dhg;
+ struct sshdh *dh = NULL;
if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
(f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
logit("WARNING: %s does not exist, using fixed modulus",
_PATH_DH_MODULI);
- return (dh_new_group_fallback(max));
+ goto fallback;
}
linenum = 0;
@@ -164,8 +158,8 @@ choose_dh(int min, int wantbits, int max)
linenum++;
if (!parse_prime(linenum, line, &dhg))
continue;
- BN_clear_free(dhg.g);
- BN_clear_free(dhg.p);
+ sshbn_free(dhg.g);
+ sshbn_free(dhg.p);
if (dhg.size > max || dhg.size < min)
continue;
@@ -183,7 +177,7 @@ choose_dh(int min, int wantbits, int max)
if (bestcount == 0) {
fclose(f);
logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
- return (dh_new_group_fallback(max));
+ goto fallback;
}
linenum = 0;
@@ -194,8 +188,8 @@ choose_dh(int min, int wantbits, int max)
if ((dhg.size > max || dhg.size < min) ||
dhg.size != best ||
linenum++ != which) {
- BN_clear_free(dhg.g);
- BN_clear_free(dhg.p);
+ sshbn_free(dhg.g);
+ sshbn_free(dhg.p);
continue;
}
break;
@@ -204,187 +198,181 @@ choose_dh(int min, int wantbits, int max)
if (linenum != which+1) {
logit("WARNING: line %d disappeared in %s, giving up",
which, _PATH_DH_PRIMES);
- return (dh_new_group_fallback(max));
+ fallback:
+ if ((r = dh_new_group_fallback(max, &dh)) != 0)
+ fatal("%s: dh_new_group_fallback: %s",
+ __func__, ssh_err(r));
+ return dh;
}
- return (dh_new_group(dhg.g, dhg.p));
+ return (sshdh_new_group(dhg.g, dhg.p));
}
/* diffie-hellman-groupN-sha1 */
-
int
-dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
+dh_pub_is_valid(struct sshdh *dh, struct sshbn *dh_pub)
{
- int i;
- int n = BN_num_bits(dh_pub);
- int bits_set = 0;
- BIGNUM *tmp;
+ size_t i;
+ size_t n;
+ int r, freeme = 0, bits_set = 0;
+ struct sshbn *dh_p = NULL, *tmp = NULL;
- if (dh_pub->neg) {
- logit("invalid public DH value: negative");
- return 0;
+ if (dh_pub == NULL) {
+ if ((dh_pub = sshdh_pubkey(dh)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ freeme = 1;
}
- if (BN_cmp(dh_pub, BN_value_one()) != 1) { /* pub_exp <= 1 */
+ n = sshbn_bits(dh_pub);
+ if (sshbn_cmp(dh_pub, sshbn_value_1()) != 1) { /* pub_exp <= 1 */
logit("invalid public DH value: <= 1");
- return 0;
+ r = SSH_ERR_INVALID_FORMAT;
+ goto out;
}
-
- if ((tmp = BN_new()) == NULL) {
- error("%s: BN_new failed", __func__);
- return 0;
+ if ((dh_p = sshdh_p(dh)) == NULL) {
+ error("%s: sshdh_p failed", __func__);
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
}
- if (!BN_sub(tmp, dh->p, BN_value_one()) ||
- BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
- BN_clear_free(tmp);
+ if ((tmp = sshbn_new()) == NULL) {
+ error("%s: sshbn_new failed", __func__);
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if ((r = sshbn_sub(tmp, dh_p, sshbn_value_1())) != 0) {
+ error("%s: sshbn_sub: %s", __func__, ssh_err(r));
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if ((r = sshbn_cmp(dh_pub, tmp)) != -1) { /* pub_exp > p-2 */
logit("invalid public DH value: >= p-1");
- return 0;
+ r = SSH_ERR_INVALID_FORMAT;
+ goto out;
}
- BN_clear_free(tmp);
-
for (i = 0; i <= n; i++)
- if (BN_is_bit_set(dh_pub, i))
+ if (sshbn_is_bit_set(dh_pub, i))
bits_set++;
- debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
+ debug2("bits set: %d/%zu", bits_set, sshbn_bits(dh_p));
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
- if (bits_set > 1)
- return 1;
+ if (bits_set <= 1) {
+ logit("invalid public DH value (%d/%zu)",
+ bits_set, sshbn_bits(dh_p));
+ r = SSH_ERR_INVALID_FORMAT;
+ goto out;
+ }
- logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
+ /* success */
+ r = 0;
+out:
+ sshbn_free(dh_p);
+ sshbn_free(tmp);
+ if (freeme)
+ sshbn_free(dh_pub);
+ return r;
+}
+
+int
+dh_gen_key(struct sshdh *dh, u_int need)
+{
+ size_t pbits;
+ struct sshbn *dh_p;
+ int r;
+
+ if ((dh_p = sshdh_p(dh)) == NULL) {
+ error("%s: sshdh_p failed", __func__);
+ return 0;
+ }
+ if (need == 0 ||
+ (pbits = sshbn_bits(dh_p)) == 0 ||
+ need > INT_MAX / 2 || 2 * need > pbits) {
+ sshbn_free(dh_p);
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
+ if ((r = sshdh_generate(dh, MIN(need * 2, pbits - 1))) != 0 ||
+ (r = dh_pub_is_valid(dh, NULL)) != 0)
+ return r;
return 0;
}
int
-dh_gen_key(DH *dh, int need)
-{
- int pbits;
-
- if (need < 0 || dh->p == NULL ||
- (pbits = BN_num_bits(dh->p)) <= 0 ||
- need > INT_MAX / 2 || 2 * need > pbits)
- return SSH_ERR_INVALID_ARGUMENT;
- dh->length = MIN(need * 2, pbits - 1);
- if (DH_generate_key(dh) == 0 ||
- !dh_pub_is_valid(dh, dh->pub_key)) {
- BN_clear_free(dh->priv_key);
- return SSH_ERR_LIBCRYPTO_ERROR;
- }
- return 0;
-}
-
-DH *
-dh_new_group_asc(const char *gen, const char *modulus)
-{
- DH *dh;
-
- if ((dh = DH_new()) == NULL)
- return NULL;
- if (BN_hex2bn(&dh->p, modulus) == 0 ||
- BN_hex2bn(&dh->g, gen) == 0) {
- DH_free(dh);
- return NULL;
- }
- return (dh);
-}
-
-/*
- * This just returns the group, we still need to generate the exchange
- * value.
- */
-
-DH *
-dh_new_group(BIGNUM *gen, BIGNUM *modulus)
-{
- DH *dh;
-
- if ((dh = DH_new()) == NULL)
- return NULL;
- dh->p = modulus;
- dh->g = gen;
-
- return (dh);
-}
-
-DH *
-dh_new_group1(void)
+dh_new_group1(struct sshdh **dhp)
{
static char *gen = "2", *group1 =
- "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
- "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
- "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
- "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
- "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
- "FFFFFFFF" "FFFFFFFF";
+ "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
+ "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
+ "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
+ "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
+ "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
+ "FFFFFFFF" "FFFFFFFF";
- return (dh_new_group_asc(gen, group1));
+ return sshdh_new_group_hex(gen, group1, dhp);
}
-DH *
-dh_new_group14(void)
+int
+dh_new_group14(struct sshdh **dhp)
{
static char *gen = "2", *group14 =
- "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
- "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
- "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
- "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
- "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
- "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
- "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
- "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
- "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
- "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
- "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
+ "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
+ "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
+ "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
+ "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
+ "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
+ "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
+ "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
+ "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
+ "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
+ "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
+ "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
- return (dh_new_group_asc(gen, group14));
+ return sshdh_new_group_hex(gen, group14, dhp);
}
/*
- * 4k bit fallback group used by DH-GEX if moduli file cannot be read.
- * Source: MODP group 16 from RFC3526.
- */
-DH *
-dh_new_group_fallback(int max)
+* 4k bit fallback group used by DH-GEX if moduli file cannot be read.
+* Source: MODP group 16 from RFC3526.
+*/
+int
+dh_new_group_fallback(int max, struct sshdh **dhp)
{
static char *gen = "2", *group16 =
- "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
- "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
- "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
- "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
- "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
- "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
- "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
- "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
- "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
- "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
- "15728E5A" "8AAAC42D" "AD33170D" "04507A33" "A85521AB" "DF1CBA64"
- "ECFB8504" "58DBEF0A" "8AEA7157" "5D060C7D" "B3970F85" "A6E1E4C7"
- "ABF5AE8C" "DB0933D7" "1E8C94E0" "4A25619D" "CEE3D226" "1AD2EE6B"
- "F12FFA06" "D98A0864" "D8760273" "3EC86A64" "521F2B18" "177B200C"
- "BBE11757" "7A615D6C" "770988C0" "BAD946E2" "08E24FA0" "74E5AB31"
- "43DB5BFC" "E0FD108E" "4B82D120" "A9210801" "1A723C12" "A787E6D7"
- "88719A10" "BDBA5B26" "99C32718" "6AF4E23C" "1A946834" "B6150BDA"
- "2583E9CA" "2AD44CE8" "DBBBC2DB" "04DE8EF9" "2E8EFC14" "1FBECAA6"
- "287C5947" "4E6BC05D" "99B2964F" "A090C3A2" "233BA186" "515BE7ED"
- "1F612970" "CEE2D7AF" "B81BDD76" "2170481C" "D0069127" "D5B05AA9"
- "93B4EA98" "8D8FDDC1" "86FFB7DC" "90A6C08F" "4DF435C9" "34063199"
- "FFFFFFFF" "FFFFFFFF";
+ "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
+ "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
+ "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
+ "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
+ "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
+ "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
+ "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
+ "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
+ "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
+ "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
+ "15728E5A" "8AAAC42D" "AD33170D" "04507A33" "A85521AB" "DF1CBA64"
+ "ECFB8504" "58DBEF0A" "8AEA7157" "5D060C7D" "B3970F85" "A6E1E4C7"
+ "ABF5AE8C" "DB0933D7" "1E8C94E0" "4A25619D" "CEE3D226" "1AD2EE6B"
+ "F12FFA06" "D98A0864" "D8760273" "3EC86A64" "521F2B18" "177B200C"
+ "BBE11757" "7A615D6C" "770988C0" "BAD946E2" "08E24FA0" "74E5AB31"
+ "43DB5BFC" "E0FD108E" "4B82D120" "A9210801" "1A723C12" "A787E6D7"
+ "88719A10" "BDBA5B26" "99C32718" "6AF4E23C" "1A946834" "B6150BDA"
+ "2583E9CA" "2AD44CE8" "DBBBC2DB" "04DE8EF9" "2E8EFC14" "1FBECAA6"
+ "287C5947" "4E6BC05D" "99B2964F" "A090C3A2" "233BA186" "515BE7ED"
+ "1F612970" "CEE2D7AF" "B81BDD76" "2170481C" "D0069127" "D5B05AA9"
+ "93B4EA98" "8D8FDDC1" "86FFB7DC" "90A6C08F" "4DF435C9" "34063199"
+ "FFFFFFFF" "FFFFFFFF";
if (max < 4096) {
debug3("requested max size %d, using 2k bit group 14", max);
- return dh_new_group14();
+ return dh_new_group14(dhp);
}
debug3("using 4k bit group 16");
- return (dh_new_group_asc(gen, group16));
+ return sshdh_new_group_hex(gen, group16, dhp);
}
/*
- * Estimates the group order for a Diffie-Hellman group that has an
- * attack complexity approximately the same as O(2**bits).
- * Values from NIST Special Publication 800-57: Recommendation for Key
- * Management Part 1 (rev 3) limited by the recommended maximum value
- * from RFC4419 section 3.
- */
-
+* Estimates the group order for a Diffie-Hellman group that has an
+* attack complexity approximately the same as O(2**bits).
+* Values from NIST Special Publication 800-57: Recommendation for Key
+* Management Part 1 (rev 3) limited by the recommended maximum value
+* from RFC4419 section 3.
+*/
u_int
dh_estimate(int bits)
{
diff --git a/dh.h b/dh.h
index 6546953..bff6720 100644
--- a/dh.h
+++ b/dh.h
@@ -26,32 +26,35 @@
#ifndef DH_H
#define DH_H
+#include
+
struct dhgroup {
- int size;
- BIGNUM *g;
- BIGNUM *p;
+ size_t size;
+ struct sshbn *g;
+ struct sshbn *p;
};
-DH *choose_dh(int, int, int);
-DH *dh_new_group_asc(const char *, const char *);
-DH *dh_new_group(BIGNUM *, BIGNUM *);
-DH *dh_new_group1(void);
-DH *dh_new_group14(void);
-DH *dh_new_group_fallback(int);
+struct sshdh *choose_dh(u_int, u_int, u_int);
+int dh_new_group1(struct sshdh **dhp);
+int dh_new_group14(struct sshdh **dhp);
+int dh_new_group_fallback(int, struct sshdh **dhp);
-int dh_gen_key(DH *, int);
-int dh_pub_is_valid(DH *, BIGNUM *);
+int dh_gen_key(struct sshdh *dh, u_int);
+int dh_pub_is_valid(struct sshdh *dh, struct sshbn *dh_pub);
u_int dh_estimate(int);
-/* Min and max values from RFC4419. */
-#define DH_GRP_MIN 1024
+/*
+* Max value from RFC4419.
+* Miniumum increased in light of DH precomputation attacks.
+*/
+#define DH_GRP_MIN 2048
#define DH_GRP_MAX 8192
/*
- * Values for "type" field of moduli(5)
- * Specifies the internal structure of the prime modulus.
- */
+* Values for "type" field of moduli(5)
+* Specifies the internal structure of the prime modulus.
+*/
#define MODULI_TYPE_UNKNOWN (0)
#define MODULI_TYPE_UNSTRUCTURED (1)
#define MODULI_TYPE_SAFE (2)
@@ -60,10 +63,10 @@ u_int dh_estimate(int);
#define MODULI_TYPE_STRONG (5)
/*
- * Values for "tests" field of moduli(5)
- * Specifies the methods used in checking for primality.
- * Usually, more than one test is used.
- */
+* Values for "tests" field of moduli(5)
+* Specifies the methods used in checking for primality.
+* Usually, more than one test is used.
+*/
#define MODULI_TESTS_UNTESTED (0x00)
#define MODULI_TESTS_COMPOSITE (0x01)
#define MODULI_TESTS_SIEVE (0x02)
@@ -71,5 +74,4 @@ u_int dh_estimate(int);
#define MODULI_TESTS_JACOBI (0x08)
#define MODULI_TESTS_ELLIPTIC (0x10)
-
#endif
diff --git a/kex.c b/kex.c
index 5100c66..9bd5eb8 100644
--- a/kex.c
+++ b/kex.c
@@ -55,18 +55,23 @@
#include "sshbuf.h"
#include "digest.h"
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
-# if defined(HAVE_EVP_SHA256)
-# define evp_ssh_sha256 EVP_sha256
-# else
-extern const EVP_MD *evp_ssh_sha256(void);
-# endif
-#endif
-
-/* prototype */
+ /* prototype */
static int kex_choose_conf(struct ssh *);
static int kex_input_newkeys(int, u_int32_t, void *);
+static const char *proposal_names[PROPOSAL_MAX] = {
+ "KEX algorithms",
+ "host key algorithms",
+ "ciphers ctos",
+ "ciphers stoc",
+ "MACs ctos",
+ "MACs stoc",
+ "compression ctos",
+ "compression stoc",
+ "languages ctos",
+ "languages stoc",
+};
+
struct kexalg {
char *name;
u_int type;
@@ -75,27 +80,19 @@ struct kexalg {
};
static const struct kexalg kexalgs[] = {
#ifdef WITH_OPENSSL
- { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
- { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
- { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
-#ifdef HAVE_EVP_SHA256
- { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
-#endif /* HAVE_EVP_SHA256 */
-#ifdef OPENSSL_HAS_ECC
- { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
- NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
- { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
- SSH_DIGEST_SHA384 },
-# ifdef OPENSSL_HAS_NISTP521
- { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
- SSH_DIGEST_SHA512 },
-# endif /* OPENSSL_HAS_NISTP521 */
-#endif /* OPENSSL_HAS_ECC */
-#endif /* WITH_OPENSSL */
-#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
- { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
-#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
- { NULL, -1, -1, -1},
+{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
+{ KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
+{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
+{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
+{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
+NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
+{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
+SSH_DIGEST_SHA384 },
+{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
+SSH_DIGEST_SHA512 },
+#endif
+{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
+{ NULL, -1, -1, -1 },
};
char *
@@ -143,7 +140,7 @@ kex_names_valid(const char *names)
if ((s = cp = strdup(names)) == NULL)
return 0;
for ((p = strsep(&cp, ",")); p && *p != '\0';
- (p = strsep(&cp, ","))) {
+ (p = strsep(&cp, ","))) {
if (kex_alg_by_name(p) == NULL) {
error("Unsupported KEX algorithm \"%.100s\"", p);
free(s);
@@ -156,9 +153,9 @@ kex_names_valid(const char *names)
}
/*
- * Concatenate algorithm names, avoiding duplicates in the process.
- * Caller must free returned string.
- */
+* Concatenate algorithm names, avoiding duplicates in the process.
+* Caller must free returned string.
+*/
char *
kex_names_cat(const char *a, const char *b)
{
@@ -169,11 +166,11 @@ kex_names_cat(const char *a, const char *b)
return NULL;
if (b == NULL || *b == '\0')
return strdup(a);
- if (strlen(b) > 1024*1024)
+ if (strlen(b) > 1024 * 1024)
return NULL;
len = strlen(a) + strlen(b) + 2;
if ((tmp = cp = strdup(b)) == NULL ||
- (ret = calloc(1, len)) == NULL) {
+ (ret = calloc(1, len)) == NULL) {
free(tmp);
return NULL;
}
@@ -182,7 +179,7 @@ kex_names_cat(const char *a, const char *b)
if (match_list(ret, p, NULL) != NULL)
continue; /* Algorithm already present */
if (strlcat(ret, ",", len) >= len ||
- strlcat(ret, p, len) >= len) {
+ strlcat(ret, p, len) >= len) {
free(tmp);
free(ret);
return NULL; /* Shouldn't happen */
@@ -193,10 +190,10 @@ kex_names_cat(const char *a, const char *b)
}
/*
- * Assemble a list of algorithms from a default list and a string from a
- * configuration file. The user-provided string may begin with '+' to
- * indicate that it should be appended to the default.
- */
+* Assemble a list of algorithms from a default list and a string from a
+* configuration file. The user-provided string may begin with '+' to
+* indicate that it should be appended to the default.
+*/
int
kex_assemble_names(const char *def, char **list)
{
@@ -227,9 +224,9 @@ kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
sshbuf_reset(b);
/*
- * add a dummy cookie, the cookie will be overwritten by
- * kex_send_kexinit(), each time a kexinit is set
- */
+ * add a dummy cookie, the cookie will be overwritten by
+ * kex_send_kexinit(), each time a kexinit is set
+ */
for (i = 0; i < KEX_COOKIE_LEN; i++) {
if ((r = sshbuf_put_u8(b, 0)) != 0)
return r;
@@ -239,7 +236,7 @@ kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
return r;
}
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */
- (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */
+ (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */
return r;
return 0;
}
@@ -267,19 +264,19 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
for (i = 0; i < PROPOSAL_MAX; i++) {
if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
goto out;
- debug2("kex_parse_kexinit: %s", proposal[i]);
+ debug2("%s: %s", proposal_names[i], proposal[i]);
}
/* first kex follows / reserved */
if ((r = sshbuf_get_u8(b, &v)) != 0 ||
- (r = sshbuf_get_u32(b, &i)) != 0)
+ (r = sshbuf_get_u32(b, &i)) != 0)
goto out;
if (first_kex_follows != NULL)
*first_kex_follows = i;
- debug2("kex_parse_kexinit: first_kex_follows %d ", v);
- debug2("kex_parse_kexinit: reserved %u ", i);
+ debug2("first_kex_follows %d ", v);
+ debug2("reserved %u ", i);
r = 0;
*propp = proposal;
- out:
+out:
if (r != 0 && proposal != NULL)
kex_prop_free(proposal);
sshbuf_free(b);
@@ -302,7 +299,14 @@ kex_prop_free(char **proposal)
static int
kex_protocol_error(int type, u_int32_t seq, void *ctxt)
{
- error("Hm, kex protocol error: type %d seq %u", type, seq);
+ struct ssh *ssh = active_state; /* XXX */
+ int r;
+
+ error("kex protocol error: type %d seq %u", type, seq);
+ if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
+ (r = sshpkt_put_u32(ssh, seq)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ return r;
return 0;
}
@@ -310,7 +314,7 @@ static void
kex_reset_dispatch(struct ssh *ssh)
{
ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN,
- SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
+ SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
@@ -321,7 +325,7 @@ kex_send_newkeys(struct ssh *ssh)
kex_reset_dispatch(ssh);
if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ (r = sshpkt_send(ssh)) != 0)
return r;
debug("SSH2_MSG_NEWKEYS sent");
debug("expecting SSH2_MSG_NEWKEYS");
@@ -370,8 +374,8 @@ kex_send_kexinit(struct ssh *ssh)
arc4random_buf(cookie, KEX_COOKIE_LEN);
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
- (r = sshpkt_putb(ssh, kex->my)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ (r = sshpkt_putb(ssh, kex->my)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
return r;
debug("SSH2_MSG_KEXINIT sent");
kex->flags |= KEX_INIT_SENT;
@@ -405,19 +409,19 @@ kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0)
return r;
/*
- * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
- * KEX method has the server move first, but a server might be using
- * a custom method or one that we otherwise don't support. We should
- * be prepared to remember first_kex_follows here so we can eat a
- * packet later.
- * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
- * for cases where the server *doesn't* go first. I guess we should
- * ignore it when it is set for these cases, which is what we do now.
- */
+ * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
+ * KEX method has the server move first, but a server might be using
+ * a custom method or one that we otherwise don't support. We should
+ * be prepared to remember first_kex_follows here so we can eat a
+ * packet later.
+ * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
+ * for cases where the server *doesn't* go first. I guess we should
+ * ignore it when it is set for these cases, which is what we do now.
+ */
if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */
- (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */
- (r = sshpkt_get_end(ssh)) != 0)
- return r;
+ (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */
+ (r = sshpkt_get_end(ssh)) != 0)
+ return r;
if (!(kex->flags & KEX_INIT_SENT))
if ((r = kex_send_kexinit(ssh)) != 0)
@@ -441,7 +445,7 @@ kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
if ((kex = calloc(1, sizeof(*kex))) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((kex->peer = sshbuf_new()) == NULL ||
- (kex->my = sshbuf_new()) == NULL) {
+ (kex->my = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
@@ -451,7 +455,7 @@ kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
kex_reset_dispatch(ssh);
r = 0;
*kexp = kex;
- out:
+out:
if (r != 0)
kex_free(kex);
return r;
@@ -468,7 +472,7 @@ kex_free_newkeys(struct newkeys *newkeys)
newkeys->enc.key = NULL;
}
if (newkeys->enc.iv) {
- explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size);
+ explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len);
free(newkeys->enc.iv);
newkeys->enc.iv = NULL;
}
@@ -494,13 +498,10 @@ kex_free(struct kex *kex)
u_int mode;
#ifdef WITH_OPENSSL
- if (kex->dh)
- DH_free(kex->dh);
-#ifdef OPENSSL_HAS_ECC
+ sshdh_free(kex->dh);
if (kex->ec_client_key)
EC_KEY_free(kex->ec_client_key);
-#endif /* OPENSSL_HAS_ECC */
-#endif /* WITH_OPENSSL */
+#endif
for (mode = 0; mode < MODE_MAX; mode++) {
kex_free_newkeys(kex->newkeys[mode]);
kex->newkeys[mode] = NULL;
@@ -575,11 +576,14 @@ choose_comp(struct sshcomp *comp, char *client, char *server)
return SSH_ERR_NO_COMPRESS_ALG_MATCH;
if (strcmp(name, "zlib@openssh.com") == 0) {
comp->type = COMP_DELAYED;
- } else if (strcmp(name, "zlib") == 0) {
+ }
+ else if (strcmp(name, "zlib") == 0) {
comp->type = COMP_ZLIB;
- } else if (strcmp(name, "none") == 0) {
+ }
+ else if (strcmp(name, "none") == 0) {
comp->type = COMP_NONE;
- } else {
+ }
+ else {
return SSH_ERR_INTERNAL_ERROR;
}
comp->name = name;
@@ -593,6 +597,7 @@ choose_kex(struct kex *k, char *client, char *server)
k->name = match_list(client, server, NULL);
+ debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
if (k->name == NULL)
return SSH_ERR_NO_KEX_ALG_MATCH;
if ((kexalg = kex_alg_by_name(k->name)) == NULL)
@@ -608,6 +613,8 @@ choose_hostkeyalg(struct kex *k, char *client, char *server)
{
char *hostkeyalg = match_list(client, server, NULL);
+ debug("kex: host key algorithm: %s",
+ hostkeyalg ? hostkeyalg : "(no match)");
if (hostkeyalg == NULL)
return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
k->hostkey_type = sshkey_type_from_name(hostkeyalg);
@@ -634,7 +641,7 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
*p = '\0';
if (strcmp(my[*idx], peer[*idx]) != 0) {
debug2("proposal mismatch: my %s peer %s",
- my[*idx], peer[*idx]);
+ my[*idx], peer[*idx]);
return (0);
}
}
@@ -653,22 +660,26 @@ kex_choose_conf(struct ssh *ssh)
u_int mode, ctos, need, dh_need, authlen;
int r, first_kex_follows;
- if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 ||
- (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
+ debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
+ if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
+ goto out;
+ debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server");
+ if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
goto out;
if (kex->server) {
- cprop=peer;
- sprop=my;
- } else {
- cprop=my;
- sprop=peer;
+ cprop = peer;
+ sprop = my;
+ }
+ else {
+ cprop = my;
+ sprop = peer;
}
/* Check whether server offers roaming */
if (!kex->server) {
char *roaming = match_list(KEX_RESUME,
- peer[PROPOSAL_KEX_ALGS], NULL);
+ peer[PROPOSAL_KEX_ALGS], NULL);
if (roaming) {
kex->roaming = 1;
@@ -677,6 +688,18 @@ kex_choose_conf(struct ssh *ssh)
}
/* Algorithm Negotiation */
+ if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
+ sprop[PROPOSAL_KEX_ALGS])) != 0) {
+ kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
+ peer[PROPOSAL_KEX_ALGS] = NULL;
+ goto out;
+ }
+ if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
+ sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
+ kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
+ peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
+ goto out;
+ }
for (mode = 0; mode < MODE_MAX; mode++) {
if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
@@ -684,12 +707,12 @@ kex_choose_conf(struct ssh *ssh)
}
kex->newkeys[mode] = newkeys;
ctos = (!kex->server && mode == MODE_OUT) ||
- (kex->server && mode == MODE_IN);
- nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
- nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
+ (kex->server && mode == MODE_IN);
+ nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
+ nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
if ((r = choose_enc(&newkeys->enc, cprop[nenc],
- sprop[nenc])) != 0) {
+ sprop[nenc])) != 0) {
kex->failed_choice = peer[nenc];
peer[nenc] = NULL;
goto out;
@@ -697,35 +720,23 @@ kex_choose_conf(struct ssh *ssh)
authlen = cipher_authlen(newkeys->enc.cipher);
/* ignore mac for authenticated encryption */
if (authlen == 0 &&
- (r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
- sprop[nmac])) != 0) {
+ (r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
+ sprop[nmac])) != 0) {
kex->failed_choice = peer[nmac];
peer[nmac] = NULL;
goto out;
}
if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
- sprop[ncomp])) != 0) {
+ sprop[ncomp])) != 0) {
kex->failed_choice = peer[ncomp];
peer[ncomp] = NULL;
goto out;
}
- debug("kex: %s %s %s %s",
- ctos ? "client->server" : "server->client",
- newkeys->enc.name,
- authlen == 0 ? newkeys->mac.name : "",
- newkeys->comp.name);
- }
- if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
- sprop[PROPOSAL_KEX_ALGS])) != 0) {
- kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
- peer[PROPOSAL_KEX_ALGS] = NULL;
- goto out;
- }
- if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
- sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
- kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
- peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
- goto out;
+ debug("kex: %s cipher: %s MAC: %s compression: %s",
+ ctos ? "client->server" : "server->client",
+ newkeys->enc.name,
+ authlen == 0 ? newkeys->mac.name : "",
+ newkeys->comp.name);
}
need = dh_need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
@@ -745,10 +756,10 @@ kex_choose_conf(struct ssh *ssh)
/* ignore the next message if the proposals do not match */
if (first_kex_follows && !proposals_match(my, peer) &&
- !(ssh->compat & SSH_BUG_FIRSTKEX))
+ !(ssh->compat & SSH_BUG_FIRSTKEX))
ssh->dispatch_skip_packets = 1;
r = 0;
- out:
+out:
kex_prop_free(my);
kex_prop_free(peer);
return r;
@@ -756,7 +767,7 @@ kex_choose_conf(struct ssh *ssh)
static int
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
- const struct sshbuf *shared_secret, u_char **keyp)
+ const struct sshbuf *shared_secret, u_char **keyp)
{
struct kex *kex = ssh->kex;
struct ssh_digest_ctx *hashctx = NULL;
@@ -775,12 +786,12 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
/* K1 = HASH(K || H || "A" || session_id) */
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
- ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
- ssh_digest_update(hashctx, hash, hashlen) != 0 ||
- ssh_digest_update(hashctx, &c, 1) != 0 ||
- ssh_digest_update(hashctx, kex->session_id,
- kex->session_id_len) != 0 ||
- ssh_digest_final(hashctx, digest, mdsz) != 0) {
+ ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
+ ssh_digest_update(hashctx, hash, hashlen) != 0 ||
+ ssh_digest_update(hashctx, &c, 1) != 0 ||
+ ssh_digest_update(hashctx, kex->session_id,
+ kex->session_id_len) != 0 ||
+ ssh_digest_final(hashctx, digest, mdsz) != 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -788,16 +799,16 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
hashctx = NULL;
/*
- * expand key:
- * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
- * Key = K1 || K2 || ... || Kn
- */
+ * expand key:
+ * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
+ * Key = K1 || K2 || ... || Kn
+ */
for (have = mdsz; need > have; have += mdsz) {
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
- ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
- ssh_digest_update(hashctx, hash, hashlen) != 0 ||
- ssh_digest_update(hashctx, digest, have) != 0 ||
- ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
+ ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
+ ssh_digest_update(hashctx, hash, hashlen) != 0 ||
+ ssh_digest_update(hashctx, digest, have) != 0 ||
+ ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -811,7 +822,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
*keyp = digest;
digest = NULL;
r = 0;
- out:
+out:
if (digest)
free(digest);
ssh_digest_free(hashctx);
@@ -821,7 +832,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
#define NKEYS 6
int
kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
- const struct sshbuf *shared_secret)
+ const struct sshbuf *shared_secret)
{
struct kex *kex = ssh->kex;
u_char *keys[NKEYS];
@@ -829,8 +840,8 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
int r;
for (i = 0; i < NKEYS; i++) {
- if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen,
- shared_secret, &keys[i])) != 0) {
+ if ((r = derive_key(ssh, 'A' + i, kex->we_need, hash, hashlen,
+ shared_secret, &keys[i])) != 0) {
for (j = 0; j < i; j++)
free(keys[j]);
return r;
@@ -838,8 +849,8 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
}
for (mode = 0; mode < MODE_MAX; mode++) {
ctos = (!kex->server && mode == MODE_OUT) ||
- (kex->server && mode == MODE_IN);
- kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1];
+ (kex->server && mode == MODE_IN);
+ kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1];
kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3];
kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5];
}
@@ -849,14 +860,14 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
#ifdef WITH_OPENSSL
int
kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
- const BIGNUM *secret)
+ const struct sshbn *secret)
{
struct sshbuf *shared_secret;
int r;
if ((shared_secret = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
- if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0)
+ if ((r = sshbuf_put_bignum2_wrap(shared_secret, secret)) == 0)
r = kex_derive_keys(ssh, hash, hashlen, shared_secret);
sshbuf_free(shared_secret);
return r;
@@ -866,7 +877,7 @@ kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
#ifdef WITH_SSH1
int
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
- u_int8_t cookie[8], u_int8_t id[16])
+ u_int8_t cookie[8], u_int8_t id[16])
{
u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
struct ssh_digest_ctx *hashctx = NULL;
@@ -876,10 +887,10 @@ derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
hlen = BN_num_bytes(host_modulus);
slen = BN_num_bytes(server_modulus);
if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) ||
- slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
+ slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
return SSH_ERR_KEY_BITS_MISMATCH;
if (BN_bn2bin(host_modulus, hbuf) <= 0 ||
- BN_bn2bin(server_modulus, sbuf) <= 0) {
+ BN_bn2bin(server_modulus, sbuf) <= 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -888,15 +899,15 @@ derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
goto out;
}
if (ssh_digest_update(hashctx, hbuf, hlen) != 0 ||
- ssh_digest_update(hashctx, sbuf, slen) != 0 ||
- ssh_digest_update(hashctx, cookie, 8) != 0 ||
- ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
+ ssh_digest_update(hashctx, sbuf, slen) != 0 ||
+ ssh_digest_update(hashctx, cookie, 8) != 0 ||
+ ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
r = 0;
- out:
+out:
ssh_digest_free(hashctx);
explicit_bzero(hbuf, sizeof(hbuf));
explicit_bzero(sbuf, sizeof(sbuf));
diff --git a/kex.h b/kex.h
index d71b532..1c2be3e 100644
--- a/kex.h
+++ b/kex.h
@@ -34,20 +34,6 @@
#include "leakmalloc.h"
#endif
-#ifdef WITH_OPENSSL
-# ifdef OPENSSL_HAS_ECC
-# include
-# else /* OPENSSL_HAS_ECC */
-# define EC_KEY void
-# define EC_GROUP void
-# define EC_POINT void
-# endif /* OPENSSL_HAS_ECC */
-#else /* WITH_OPENSSL */
-# define EC_KEY void
-# define EC_GROUP void
-# define EC_POINT void
-#endif /* WITH_OPENSSL */
-
#define KEX_COOKIE_LEN 16
#define KEX_DH1 "diffie-hellman-group1-sha1"
@@ -142,15 +128,15 @@ struct kex {
char *client_version_string;
char *server_version_string;
char *failed_choice;
- int (*verify_host_key)(struct sshkey *, struct ssh *);
+ int(*verify_host_key)(struct sshkey *, struct ssh *);
struct sshkey *(*load_host_public_key)(int, int, struct ssh *);
struct sshkey *(*load_host_private_key)(int, int, struct ssh *);
- int (*host_key_index)(struct sshkey *, int, struct ssh *);
- int (*sign)(struct sshkey *, struct sshkey *,
- u_char **, size_t *, const u_char *, size_t, u_int);
- int (*kex[KEX_MAX])(struct ssh *);
+ int(*host_key_index)(struct sshkey *, int, struct ssh *);
+ int(*sign)(struct sshkey *, struct sshkey *,
+ u_char **, size_t *, const u_char *, size_t, u_int);
+ int(*kex[KEX_MAX])(struct ssh *);
/* kex specific state */
- DH *dh; /* DH */
+ struct sshdh *dh; /* DH */
u_int min, max, nbits; /* GEX */
EC_KEY *ec_client_key; /* ECDH */
const EC_GROUP *ec_group; /* ECDH */
@@ -175,7 +161,8 @@ void kex_prop_free(char **);
int kex_send_kexinit(struct ssh *);
int kex_input_kexinit(int, u_int32_t, void *);
int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *);
-int kex_derive_keys_bn(struct ssh *, u_char *, u_int, const BIGNUM *);
+int kex_derive_keys_bn(struct ssh *, u_char *, u_int,
+ const struct sshbn *);
int kex_send_newkeys(struct ssh *);
int kexdh_client(struct ssh *);
@@ -188,29 +175,30 @@ int kexc25519_client(struct ssh *);
int kexc25519_server(struct ssh *);
int kex_dh_hash(const char *, const char *,
- const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
- const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *);
+ const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
+ const struct sshbn *, const struct sshbn *,
+ const struct sshbn *, u_char *, size_t *);
int kexgex_hash(int, const char *, const char *,
- const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
- int, int, int,
- const BIGNUM *, const BIGNUM *, const BIGNUM *,
- const BIGNUM *, const BIGNUM *,
- u_char *, size_t *);
+ const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
+ int, int, int,
+ const struct sshbn *, const struct sshbn *, const struct sshbn *,
+ const struct sshbn *, const struct sshbn *,
+ u_char *, size_t *);
int kex_ecdh_hash(int, const EC_GROUP *, const char *, const char *,
- const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
- const EC_POINT *, const EC_POINT *, const BIGNUM *, u_char *, size_t *);
+ const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
+ const EC_POINT *, const EC_POINT *, const BIGNUM *, u_char *, size_t *);
int kex_c25519_hash(int, const char *, const char *, const char *, size_t,
- const char *, size_t, const u_char *, size_t, const u_char *, const u_char *,
- const u_char *, size_t, u_char *, size_t *);
+ const char *, size_t, const u_char *, size_t, const u_char *, const u_char *,
+ const u_char *, size_t, u_char *, size_t *);
void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
- __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
- __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
+__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
+__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
int kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
- const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
+ const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
@@ -221,10 +209,4 @@ derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]);
void dump_digest(char *, u_char *, int);
#endif
-#if !defined(WITH_OPENSSL) || !defined(OPENSSL_HAS_ECC)
-# undef EC_KEY
-# undef EC_GROUP
-# undef EC_POINT
-#endif
-
#endif
diff --git a/kexdh.c b/kexdh.c
index feea669..d368fca 100644
--- a/kexdh.c
+++ b/kexdh.c
@@ -25,7 +25,6 @@
#include "includes.h"
-#ifdef WITH_OPENSSL
#include
@@ -43,15 +42,15 @@
int
kex_dh_hash(
- const char *client_version_string,
- const char *server_version_string,
- const u_char *ckexinit, size_t ckexinitlen,
- const u_char *skexinit, size_t skexinitlen,
- const u_char *serverhostkeyblob, size_t sbloblen,
- const BIGNUM *client_dh_pub,
- const BIGNUM *server_dh_pub,
- const BIGNUM *shared_secret,
- u_char *hash, size_t *hashlen)
+ const char *client_version_string,
+ const char *server_version_string,
+ const u_char *ckexinit, size_t ckexinitlen,
+ const u_char *skexinit, size_t skexinitlen,
+ const u_char *serverhostkeyblob, size_t sbloblen,
+ const struct sshbn *client_dh_pub,
+ const struct sshbn *server_dh_pub,
+ const struct sshbn *shared_secret,
+ u_char *hash, size_t *hashlen)
{
struct sshbuf *b;
int r;
@@ -61,18 +60,18 @@ kex_dh_hash(
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
- (r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
- /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
- (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 ||
- (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
- (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
- (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 ||
- (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
- (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
- (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
- (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
- (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
- (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
+ (r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
+ /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+ (r = sshbuf_put_u32(b, ckexinitlen + 1)) != 0 ||
+ (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
+ (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
+ (r = sshbuf_put_u32(b, skexinitlen + 1)) != 0 ||
+ (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
+ (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
+ (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
+ (r = sshbuf_put_bignum2_wrap(b, client_dh_pub)) != 0 ||
+ (r = sshbuf_put_bignum2_wrap(b, server_dh_pub)) != 0 ||
+ (r = sshbuf_put_bignum2_wrap(b, shared_secret)) != 0) {
sshbuf_free(b);
return r;
}
@@ -90,4 +89,3 @@ kex_dh_hash(
#endif
return 0;
}
-#endif /* WITH_OPENSSL */
diff --git a/kexdhc.c b/kexdhc.c
index af259f1..4a174b6 100644
--- a/kexdhc.c
+++ b/kexdhc.c
@@ -25,7 +25,6 @@
#include "includes.h"
-#ifdef WITH_OPENSSL
#include
@@ -55,15 +54,18 @@ int
kexdh_client(struct ssh *ssh)
{
struct kex *kex = ssh->kex;
+ struct sshbn *dh_client_pub = NULL;
int r;
/* generate and send 'e', client DH public key */
switch (kex->kex_type) {
case KEX_DH_GRP1_SHA1:
- kex->dh = dh_new_group1();
+ if ((r = dh_new_group1(&kex->dh)) != 0)
+ return r;
break;
case KEX_DH_GRP14_SHA1:
- kex->dh = dh_new_group14();
+ if ((r = dh_new_group14(&kex->dh)) != 0)
+ return r;
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
@@ -73,22 +75,25 @@ kexdh_client(struct ssh *ssh)
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
+ goto out;
+ if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
debug("sending SSH2_MSG_KEXDH_INIT");
- if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
- (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
+ (r = sshpkt_put_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
- DHparams_print_fp(stderr, kex->dh);
- fprintf(stderr, "pub= ");
- BN_print_fp(stderr, kex->dh->pub_key);
- fprintf(stderr, "\n");
+ sshdh_dump(kex->dh);
#endif
debug("expecting SSH2_MSG_KEXDH_REPLY");
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh);
r = 0;
- out:
+out:
+ sshbn_free(dh_client_pub);
return r;
}
@@ -97,12 +102,14 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
- BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+ struct sshbn *dh_client_pub = NULL;
+ struct sshbn *dh_server_pub = NULL;
+ struct sshbn *shared_secret = NULL;
struct sshkey *server_host_key = NULL;
- u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL;
+ u_char *server_host_key_blob = NULL, *signature = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
- size_t klen = 0, slen, sbloblen, hashlen;
- int kout, r;
+ size_t slen, sbloblen, hashlen;
+ int r;
if (kex->verify_host_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
@@ -110,13 +117,13 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
}
/* key, cert */
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
- &sbloblen)) != 0 ||
- (r = sshkey_from_blob(server_host_key_blob, sbloblen,
- &server_host_key)) != 0)
+ &sbloblen)) != 0 ||
+ (r = sshkey_from_blob(server_host_key_blob, sbloblen,
+ &server_host_key)) != 0)
goto out;
if (server_host_key->type != kex->hostkey_type ||
- (kex->hostkey_type == KEY_ECDSA &&
- server_host_key->ecdsa_nid != kex->hostkey_nid)) {
+ (kex->hostkey_type == KEY_ECDSA &&
+ server_host_key->ecdsa_nid != kex->hostkey_nid)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
@@ -125,14 +132,14 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
goto out;
}
/* DH parameter f, server public DH key */
- if ((dh_server_pub = BN_new()) == NULL) {
+ if ((dh_server_pub = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* signed H */
- if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
- (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ if ((r = sshpkt_get_bignum2_wrap(ssh, dh_server_pub)) != 0 ||
+ (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
@@ -140,23 +147,17 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
- if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
+ if ((r = dh_pub_is_valid(kex->dh, dh_server_pub)) != 0) {
sshpkt_disconnect(ssh, "bad server public DH value");
- r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
-
- klen = DH_size(kex->dh);
- if ((kbuf = malloc(klen)) == NULL ||
- (shared_secret = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
+ if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL) {
+ r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
- if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
- BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
- r = SSH_ERR_LIBCRYPTO_ERROR;
+ if ((r = sshdh_compute_key(kex->dh, dh_server_pub,
+ &shared_secret)) != 0)
goto out;
- }
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
@@ -164,19 +165,19 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
/* calc and verify H */
hashlen = sizeof(hash);
if ((r = kex_dh_hash(
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- server_host_key_blob, sbloblen,
- kex->dh->pub_key,
- dh_server_pub,
- shared_secret,
- hash, &hashlen)) != 0)
+ kex->client_version_string,
+ kex->server_version_string,
+ sshbuf_ptr(kex->my), sshbuf_len(kex->my),
+ sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
+ server_host_key_blob, sbloblen,
+ dh_client_pub,
+ dh_server_pub,
+ shared_secret,
+ hash, &hashlen)) != 0)
goto out;
if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
- ssh->compat)) != 0)
+ ssh->compat)) != 0)
goto out;
/* save session id */
@@ -192,21 +193,15 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
- out:
+out:
explicit_bzero(hash, sizeof(hash));
- DH_free(kex->dh);
- kex->dh = NULL;
- if (dh_server_pub)
- BN_clear_free(dh_server_pub);
- if (kbuf) {
- explicit_bzero(kbuf, klen);
- free(kbuf);
- }
- if (shared_secret)
- BN_clear_free(shared_secret);
sshkey_free(server_host_key);
+ sshbn_free(shared_secret);
+ sshbn_free(dh_server_pub);
+ sshbn_free(dh_client_pub);
+ sshdh_free(kex->dh);
+ kex->dh = NULL;
free(server_host_key_blob);
free(signature);
return r;
}
-#endif /* WITH_OPENSSL */
diff --git a/kexdhs.c b/kexdhs.c
index f510aba..06ef313 100644
--- a/kexdhs.c
+++ b/kexdhs.c
@@ -34,7 +34,6 @@
#undef KRB5
#endif
-#ifdef WITH_OPENSSL
#include
@@ -69,27 +68,24 @@ kexdh_server(struct ssh *ssh)
/* generate server DH public key */
switch (kex->kex_type) {
case KEX_DH_GRP1_SHA1:
- kex->dh = dh_new_group1();
+ if ((r = dh_new_group1(&kex->dh)) != 0)
+ return r;
break;
case KEX_DH_GRP14_SHA1:
- kex->dh = dh_new_group14();
+ if ((r = dh_new_group14(&kex->dh)) != 0)
+ return r;
break;
default:
- r = SSH_ERR_INVALID_ARGUMENT;
- goto out;
- }
- if (kex->dh == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
+ return SSH_ERR_INVALID_ARGUMENT;
}
+ if (kex->dh == NULL)
+ return SSH_ERR_ALLOC_FAIL;
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
- goto out;
+ return r;
debug("expecting SSH2_MSG_KEXDH_INIT");
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init);
- r = 0;
- out:
- return r;
+ return 0;
}
int
@@ -97,35 +93,37 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
- BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+ struct sshbn *dh_client_pub = NULL;
+ struct sshbn *dh_server_pub = NULL;
+ struct sshbn *shared_secret = NULL;
struct sshkey *server_host_public, *server_host_private;
- u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
+ u_char *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t sbloblen, slen;
- size_t klen = 0, hashlen;
- int kout, r;
+ size_t hashlen;
+ int r;
if (kex->load_host_public_key == NULL ||
- kex->load_host_private_key == NULL) {
+ kex->load_host_private_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
server_host_public = kex->load_host_public_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
+ kex->hostkey_nid, ssh);
server_host_private = kex->load_host_private_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
+ kex->hostkey_nid, ssh);
if (server_host_public == NULL) {
r = SSH_ERR_NO_HOSTKEY_LOADED;
goto out;
}
/* key, cert */
- if ((dh_client_pub = BN_new()) == NULL) {
+ if ((dh_client_pub = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ if ((r = sshpkt_get_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
@@ -136,46 +134,37 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
#endif
#ifdef DEBUG_KEXDH
- DHparams_print_fp(stderr, kex->dh);
- fprintf(stderr, "pub= ");
- BN_print_fp(stderr, kex->dh->pub_key);
- fprintf(stderr, "\n");
+ sshdh_dump(kex->dh);
#endif
- if (!dh_pub_is_valid(kex->dh, dh_client_pub)) {
+ if ((r = dh_pub_is_valid(kex->dh, dh_client_pub)) != 0) {
sshpkt_disconnect(ssh, "bad client public DH value");
- r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
-
- klen = DH_size(kex->dh);
- if ((kbuf = malloc(klen)) == NULL ||
- (shared_secret = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
+ if ((dh_server_pub = sshdh_pubkey(kex->dh)) == NULL) {
+ r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
- if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
- BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
- r = SSH_ERR_LIBCRYPTO_ERROR;
+ if ((r = sshdh_compute_key(kex->dh, dh_client_pub,
+ &shared_secret)) != 0)
goto out;
- }
#ifdef DEBUG_KEXDH
- dump_digest("shared secret", kbuf, kout);
+ dump_digest("shared secret", kbuf, klen);
#endif
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
- &sbloblen)) != 0)
+ &sbloblen)) != 0)
goto out;
/* calc H */
hashlen = sizeof(hash);
if ((r = kex_dh_hash(
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- server_host_key_blob, sbloblen,
- dh_client_pub,
- kex->dh->pub_key,
- shared_secret,
- hash, &hashlen)) != 0)
+ kex->client_version_string,
+ kex->server_version_string,
+ sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
+ sshbuf_ptr(kex->my), sshbuf_len(kex->my),
+ server_host_key_blob, sbloblen,
+ dh_client_pub,
+ dh_server_pub,
+ shared_secret,
+ hash, &hashlen)) != 0)
goto out;
/* save session id := H */
@@ -191,35 +180,29 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
/* sign H */
if ((r = kex->sign(server_host_private, server_host_public,
- &signature, &slen, hash, hashlen, ssh->compat)) < 0)
+ &signature, &slen, hash, hashlen, ssh->compat)) < 0)
goto out;
/* destroy_sensitive_data(); */
/* send server hostkey, DH pubkey 'f' and singed H */
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 ||
- (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */
- (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
+ (r = sshpkt_put_bignum2_wrap(ssh, dh_server_pub)) != 0 || /* f */
+ (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
goto out;
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
- out:
+out:
explicit_bzero(hash, sizeof(hash));
- DH_free(kex->dh);
+ sshbn_free(shared_secret);
+ sshbn_free(dh_client_pub);
+ sshbn_free(dh_server_pub);
+ sshdh_free(kex->dh);
kex->dh = NULL;
- if (dh_client_pub)
- BN_clear_free(dh_client_pub);
- if (kbuf) {
- explicit_bzero(kbuf, klen);
- free(kbuf);
- }
- if (shared_secret)
- BN_clear_free(shared_secret);
free(server_host_key_blob);
free(signature);
return r;
}
-#endif /* WITH_OPENSSL */
diff --git a/kexecdhc.c b/kexecdhc.c
index 90220ce..4c1865f 100644
--- a/kexecdhc.c
+++ b/kexecdhc.c
@@ -26,8 +26,6 @@
#include "includes.h"
-#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
-
#include
#include
@@ -72,8 +70,8 @@ kexecdh_client(struct ssh *ssh)
public_key = EC_KEY_get0_public_key(client_key);
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
- (r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ (r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
goto out;
debug("sending SSH2_MSG_KEX_ECDH_INIT");
@@ -88,7 +86,7 @@ kexecdh_client(struct ssh *ssh)
debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_ecdh_reply);
r = 0;
- out:
+out:
if (client_key)
EC_KEY_free(client_key);
return r;
@@ -103,6 +101,7 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
EC_POINT *server_public = NULL;
EC_KEY *client_key;
BIGNUM *shared_secret = NULL;
+ struct sshbn *xxx_shared_secret = NULL;
struct sshkey *server_host_key = NULL;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf = NULL;
@@ -120,13 +119,13 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
/* hostkey */
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
- &sbloblen)) != 0 ||
- (r = sshkey_from_blob(server_host_key_blob, sbloblen,
- &server_host_key)) != 0)
+ &sbloblen)) != 0 ||
+ (r = sshkey_from_blob(server_host_key_blob, sbloblen,
+ &server_host_key)) != 0)
goto out;
if (server_host_key->type != kex->hostkey_type ||
- (kex->hostkey_type == KEY_ECDSA &&
- server_host_key->ecdsa_nid != kex->hostkey_nid)) {
+ (kex->hostkey_type == KEY_ECDSA &&
+ server_host_key->ecdsa_nid != kex->hostkey_nid)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
@@ -142,8 +141,8 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
goto out;
}
if ((r = sshpkt_get_ec(ssh, server_public, group)) != 0 ||
- (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXECDH
@@ -158,13 +157,13 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
klen = (EC_GROUP_get_degree(group) + 7) / 8;
if ((kbuf = malloc(klen)) == NULL ||
- (shared_secret = BN_new()) == NULL) {
+ (shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (ECDH_compute_key(kbuf, klen, server_public,
- client_key, NULL) != (int)klen ||
- BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
+ client_key, NULL) != (int)klen ||
+ BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -175,21 +174,21 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
/* calc and verify H */
hashlen = sizeof(hash);
if ((r = kex_ecdh_hash(
- kex->hash_alg,
- group,
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- server_host_key_blob, sbloblen,
- EC_KEY_get0_public_key(client_key),
- server_public,
- shared_secret,
- hash, &hashlen)) != 0)
+ kex->hash_alg,
+ group,
+ kex->client_version_string,
+ kex->server_version_string,
+ sshbuf_ptr(kex->my), sshbuf_len(kex->my),
+ sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
+ server_host_key_blob, sbloblen,
+ EC_KEY_get0_public_key(client_key),
+ server_public,
+ shared_secret,
+ hash, &hashlen)) != 0)
goto out;
if ((r = sshkey_verify(server_host_key, signature, slen, hash,
- hashlen, ssh->compat)) != 0)
+ hashlen, ssh->compat)) != 0)
goto out;
/* save session id */
@@ -203,9 +202,15 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
memcpy(kex->session_id, hash, kex->session_id_len);
}
- if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
+ /* XXX */
+ if ((xxx_shared_secret = sshbn_from_bignum(shared_secret)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if ((r = kex_derive_keys_bn(ssh, hash, hashlen,
+ xxx_shared_secret)) == 0)
r = kex_send_newkeys(ssh);
- out:
+out:
explicit_bzero(hash, sizeof(hash));
if (kex->ec_client_key) {
EC_KEY_free(kex->ec_client_key);
@@ -219,10 +224,9 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
}
if (shared_secret)
BN_clear_free(shared_secret);
+ sshbn_free(xxx_shared_secret);
sshkey_free(server_host_key);
free(server_host_key_blob);
free(signature);
return r;
}
-#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
-
diff --git a/kexecdhs.c b/kexecdhs.c
index 0adb80e..98d66cc 100644
--- a/kexecdhs.c
+++ b/kexecdhs.c
@@ -26,7 +26,7 @@
#include "includes.h"
-#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
+
#include
#include
@@ -67,6 +67,7 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
const EC_GROUP *group;
const EC_POINT *public_key;
BIGNUM *shared_secret = NULL;
+ struct sshbn *xxx_shared_secret = NULL;
struct sshkey *server_host_private, *server_host_public;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf = NULL;
@@ -91,14 +92,14 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
#endif
if (kex->load_host_public_key == NULL ||
- kex->load_host_private_key == NULL) {
+ kex->load_host_private_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
server_host_public = kex->load_host_public_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
+ kex->hostkey_nid, ssh);
server_host_private = kex->load_host_private_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
+ kex->hostkey_nid, ssh);
if (server_host_public == NULL) {
r = SSH_ERR_NO_HOSTKEY_LOADED;
goto out;
@@ -108,7 +109,7 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
goto out;
}
if ((r = sshpkt_get_ec(ssh, client_public, group)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ (r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXECDH
@@ -124,13 +125,13 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
/* Calculate shared_secret */
klen = (EC_GROUP_get_degree(group) + 7) / 8;
if ((kbuf = malloc(klen)) == NULL ||
- (shared_secret = BN_new()) == NULL) {
+ (shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (ECDH_compute_key(kbuf, klen, client_public,
- server_key, NULL) != (int)klen ||
- BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
+ server_key, NULL) != (int)klen ||
+ BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -140,21 +141,21 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
#endif
/* calc H */
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
- &sbloblen)) != 0)
+ &sbloblen)) != 0)
goto out;
hashlen = sizeof(hash);
if ((r = kex_ecdh_hash(
- kex->hash_alg,
- group,
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- server_host_key_blob, sbloblen,
- client_public,
- EC_KEY_get0_public_key(server_key),
- shared_secret,
- hash, &hashlen)) != 0)
+ kex->hash_alg,
+ group,
+ kex->client_version_string,
+ kex->server_version_string,
+ sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
+ sshbuf_ptr(kex->my), sshbuf_len(kex->my),
+ server_host_key_blob, sbloblen,
+ client_public,
+ EC_KEY_get0_public_key(server_key),
+ shared_secret,
+ hash, &hashlen)) != 0)
goto out;
/* save session id := H */
@@ -170,7 +171,7 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
/* sign H */
if ((r = kex->sign(server_host_private, server_host_public,
- &signature, &slen, hash, hashlen, ssh->compat)) < 0)
+ &signature, &slen, hash, hashlen, ssh->compat)) < 0)
goto out;
/* destroy_sensitive_data(); */
@@ -178,15 +179,20 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
public_key = EC_KEY_get0_public_key(server_key);
/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
- (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
- (r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
- (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
+ (r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
+ (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
goto out;
-
- if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
+ /* XXX */
+ if ((xxx_shared_secret = sshbn_from_bignum(shared_secret)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if ((r = kex_derive_keys_bn(ssh, hash, hashlen,
+ xxx_shared_secret)) == 0)
r = kex_send_newkeys(ssh);
- out:
+out:
explicit_bzero(hash, sizeof(hash));
if (kex->ec_client_key) {
EC_KEY_free(kex->ec_client_key);
@@ -200,9 +206,8 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
}
if (shared_secret)
BN_clear_free(shared_secret);
+ sshbn_free(xxx_shared_secret);
free(server_host_key_blob);
free(signature);
return r;
}
-#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
-
diff --git a/kexgex.c b/kexgex.c
index 63be885..f16a439 100644
--- a/kexgex.c
+++ b/kexgex.c
@@ -35,8 +35,6 @@
#undef KRB5
#endif
-#ifdef WITH_OPENSSL
-
#include
#include
@@ -49,22 +47,23 @@
#include "ssherr.h"
#include "sshbuf.h"
#include "digest.h"
+#include "crypto-wrap.h"
int
kexgex_hash(
- int hash_alg,
- const char *client_version_string,
- const char *server_version_string,
- const u_char *ckexinit, size_t ckexinitlen,
- const u_char *skexinit, size_t skexinitlen,
- const u_char *serverhostkeyblob, size_t sbloblen,
- int min, int wantbits, int max,
- const BIGNUM *prime,
- const BIGNUM *gen,
- const BIGNUM *client_dh_pub,
- const BIGNUM *server_dh_pub,
- const BIGNUM *shared_secret,
- u_char *hash, size_t *hashlen)
+ int hash_alg,
+ const char *client_version_string,
+ const char *server_version_string,
+ const u_char *ckexinit, size_t ckexinitlen,
+ const u_char *skexinit, size_t skexinitlen,
+ const u_char *serverhostkeyblob, size_t sbloblen,
+ int min, int wantbits, int max,
+ const struct sshbn *prime,
+ const struct sshbn *gen,
+ const struct sshbn *client_dh_pub,
+ const struct sshbn *server_dh_pub,
+ const struct sshbn *shared_secret,
+ u_char *hash, size_t *hashlen)
{
struct sshbuf *b;
int r;
@@ -74,23 +73,23 @@ kexgex_hash(
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
- (r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
- /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
- (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 ||
- (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
- (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
- (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 ||
- (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
- (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
- (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
- (min != -1 && (r = sshbuf_put_u32(b, min)) != 0) ||
- (r = sshbuf_put_u32(b, wantbits)) != 0 ||
- (max != -1 && (r = sshbuf_put_u32(b, max)) != 0) ||
- (r = sshbuf_put_bignum2(b, prime)) != 0 ||
- (r = sshbuf_put_bignum2(b, gen)) != 0 ||
- (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
- (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
- (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
+ (r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
+ /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+ (r = sshbuf_put_u32(b, ckexinitlen + 1)) != 0 ||
+ (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
+ (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
+ (r = sshbuf_put_u32(b, skexinitlen + 1)) != 0 ||
+ (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
+ (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
+ (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
+ (min != -1 && (r = sshbuf_put_u32(b, min)) != 0) ||
+ (r = sshbuf_put_u32(b, wantbits)) != 0 ||
+ (max != -1 && (r = sshbuf_put_u32(b, max)) != 0) ||
+ (r = sshbuf_put_bignum2_wrap(b, prime)) != 0 ||
+ (r = sshbuf_put_bignum2_wrap(b, gen)) != 0 ||
+ (r = sshbuf_put_bignum2_wrap(b, client_dh_pub)) != 0 ||
+ (r = sshbuf_put_bignum2_wrap(b, server_dh_pub)) != 0 ||
+ (r = sshbuf_put_bignum2_wrap(b, shared_secret)) != 0) {
sshbuf_free(b);
return r;
}
@@ -108,4 +107,63 @@ kexgex_hash(
#endif
return 0;
}
-#endif /* WITH_OPENSSL */
+
+
+int
+kexgex_hash_old(
+ int hash_alg,
+ const char *client_version_string,
+ const char *server_version_string,
+ const u_char *ckexinit, size_t ckexinitlen,
+ const u_char *skexinit, size_t skexinitlen,
+ const u_char *serverhostkeyblob, size_t sbloblen,
+ int min, int wantbits, int max,
+ const BIGNUM *prime,
+ const BIGNUM *gen,
+ const BIGNUM *client_dh_pub,
+ const BIGNUM *server_dh_pub,
+ const BIGNUM *shared_secret,
+ u_char *hash, size_t *hashlen)
+{
+ struct sshbuf *b;
+ int r;
+
+ if (*hashlen < ssh_digest_bytes(SSH_DIGEST_SHA1))
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((b = sshbuf_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
+ (r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
+ /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+ (r = sshbuf_put_u32(b, ckexinitlen + 1)) != 0 ||
+ (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
+ (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
+ (r = sshbuf_put_u32(b, skexinitlen + 1)) != 0 ||
+ (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
+ (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
+ (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
+ (min != -1 && (r = sshbuf_put_u32(b, min)) != 0) ||
+ (r = sshbuf_put_u32(b, wantbits)) != 0 ||
+ (max != -1 && (r = sshbuf_put_u32(b, max)) != 0) ||
+ (r = sshbuf_put_bignum2(b, prime)) != 0 ||
+ (r = sshbuf_put_bignum2(b, gen)) != 0 ||
+ (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
+ (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
+ (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
+ sshbuf_free(b);
+ return r;
+ }
+#ifdef DEBUG_KEXDH
+ sshbuf_dump(b, stderr);
+#endif
+ if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
+ sshbuf_free(b);
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ }
+ sshbuf_free(b);
+ *hashlen = ssh_digest_bytes(hash_alg);
+#ifdef DEBUG_KEXDH
+ dump_digest("hash", hash, *hashlen);
+#endif
+ return 0;
+}
\ No newline at end of file
diff --git a/kexgexc.c b/kexgexc.c
index 71ff133..e18e9b3 100644
--- a/kexgexc.c
+++ b/kexgexc.c
@@ -26,14 +26,11 @@
#include "includes.h"
-#ifdef WITH_OPENSSL
-
#include
#include
#include
-#include
#include
#include
#include
@@ -54,6 +51,23 @@
static int input_kex_dh_gex_group(int, u_int32_t, void *);
static int input_kex_dh_gex_reply(int, u_int32_t, void *);
+int
+kexgex_hash_old(
+ int hash_alg,
+ const char *client_version_string,
+ const char *server_version_string,
+ const u_char *ckexinit, size_t ckexinitlen,
+ const u_char *skexinit, size_t skexinitlen,
+ const u_char *serverhostkeyblob, size_t sbloblen,
+ int min, int wantbits, int max,
+ const BIGNUM *prime,
+ const BIGNUM *gen,
+ const BIGNUM *client_dh_pub,
+ const BIGNUM *server_dh_pub,
+ const BIGNUM *shared_secret,
+ u_char *hash, size_t *hashlen);
+
+
int
kexgex_client(struct ssh *ssh)
{
@@ -70,21 +84,21 @@ kexgex_client(struct ssh *ssh)
kex->nbits = MIN(kex->nbits, 4096);
/* New GEX request */
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 ||
- (r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
- (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
- (r = sshpkt_put_u32(ssh, kex->max)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ (r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
+ (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
+ (r = sshpkt_put_u32(ssh, kex->max)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
goto out;
debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent",
- kex->min, kex->nbits, kex->max);
+ kex->min, kex->nbits, kex->max);
#ifdef DEBUG_KEXDH
fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
- kex->min, kex->nbits, kex->max);
+ kex->min, kex->nbits, kex->max);
#endif
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP,
- &input_kex_dh_gex_group);
+ &input_kex_dh_gex_group);
r = 0;
- out:
+out:
return r;
}
@@ -93,52 +107,55 @@ input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
- BIGNUM *p = NULL, *g = NULL;
- int r, bits;
+ struct sshbn *dh_client_pub = NULL;
+ struct sshbn *dh_g = NULL, *dh_p = NULL;
+ int r;
+ size_t bits;
debug("got SSH2_MSG_KEX_DH_GEX_GROUP");
- if ((p = BN_new()) == NULL ||
- (g = BN_new()) == NULL) {
+ if ((dh_p = sshbn_new()) == NULL ||
+ (dh_g = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if ((r = sshpkt_get_bignum2(ssh, p)) != 0 ||
- (r = sshpkt_get_bignum2(ssh, g)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ if ((r = sshpkt_get_bignum2_wrap(ssh, dh_p)) != 0 ||
+ (r = sshpkt_get_bignum2_wrap(ssh, dh_g)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
goto out;
- if ((bits = BN_num_bits(p)) < 0 ||
- (u_int)bits < kex->min || (u_int)bits > kex->max) {
+ if ((bits = sshbn_bits(dh_p)) == 0 ||
+ bits < kex->min || bits > kex->max) {
r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
goto out;
}
- if ((kex->dh = dh_new_group(g, p)) == NULL) {
+ if ((kex->dh = sshdh_new_group(dh_g, dh_p)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- p = g = NULL; /* belong to kex->dh now */
+ dh_p = dh_g = NULL; /* belong to kex->dh now */
- /* generate and send 'e', client DH public key */
- if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
- (r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ /* generate and send 'e', client DH public key */
+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
+ goto out;
+ if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL) {
+ r = SSH_ERR_INTERNAL_ERROR;
+ goto out;
+ }
+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
+ (r = sshpkt_put_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
goto out;
debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
#ifdef DEBUG_KEXDH
- DHparams_print_fp(stderr, kex->dh);
- fprintf(stderr, "pub= ");
- BN_print_fp(stderr, kex->dh->pub_key);
- fprintf(stderr, "\n");
+ sshdh_dump(kex->dh);
#endif
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL);
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply);
r = 0;
out:
- if (p)
- BN_clear_free(p);
- if (g)
- BN_clear_free(g);
+ sshbn_free(dh_p);
+ sshbn_free(dh_g);
+ sshbn_free(dh_client_pub);
return r;
}
@@ -147,12 +164,15 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
- BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+ struct sshbn *dh_g = NULL, *dh_p = NULL;
+ struct sshbn *dh_client_pub = NULL;
+ struct sshbn *dh_server_pub = NULL;
+ struct sshbn *shared_secret = NULL;
struct sshkey *server_host_key = NULL;
- u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
+ u_char *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
- size_t klen = 0, slen, sbloblen, hashlen;
- int kout, r;
+ size_t slen, sbloblen, hashlen;
+ int r;
debug("got SSH2_MSG_KEX_DH_GEX_REPLY");
if (kex->verify_host_key == NULL) {
@@ -161,17 +181,17 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
}
/* key, cert */
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
- &sbloblen)) != 0 ||
- (r = sshkey_from_blob(server_host_key_blob, sbloblen,
- &server_host_key)) != 0)
+ &sbloblen)) != 0 ||
+ (r = sshkey_from_blob(server_host_key_blob, sbloblen,
+ &server_host_key)) != 0)
goto out;
if (server_host_key->type != kex->hostkey_type) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
if (server_host_key->type != kex->hostkey_type ||
- (kex->hostkey_type == KEY_ECDSA &&
- server_host_key->ecdsa_nid != kex->hostkey_nid)) {
+ (kex->hostkey_type == KEY_ECDSA &&
+ server_host_key->ecdsa_nid != kex->hostkey_nid)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
@@ -180,14 +200,14 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
goto out;
}
/* DH parameter f, server public DH key */
- if ((dh_server_pub = BN_new()) == NULL) {
+ if ((dh_server_pub = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* signed H */
- if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
- (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ if ((r = sshpkt_get_bignum2_wrap(ssh, dh_server_pub)) != 0 ||
+ (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
@@ -195,23 +215,19 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
- if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
+ if ((r = dh_pub_is_valid(kex->dh, dh_server_pub)) != 0) {
sshpkt_disconnect(ssh, "bad server public DH value");
- r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
-
- klen = DH_size(kex->dh);
- if ((kbuf = malloc(klen)) == NULL ||
- (shared_secret = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
+ if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL ||
+ (dh_p = sshdh_p(kex->dh)) == NULL ||
+ (dh_g = sshdh_g(kex->dh)) == NULL) {
+ r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
- if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
- BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
- r = SSH_ERR_LIBCRYPTO_ERROR;
+ if ((r = sshdh_compute_key(kex->dh, dh_server_pub,
+ &shared_secret)) != 0)
goto out;
- }
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
@@ -221,22 +237,22 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
/* calc and verify H */
hashlen = sizeof(hash);
if ((r = kexgex_hash(
- kex->hash_alg,
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- server_host_key_blob, sbloblen,
- kex->min, kex->nbits, kex->max,
- kex->dh->p, kex->dh->g,
- kex->dh->pub_key,
- dh_server_pub,
- shared_secret,
- hash, &hashlen)) != 0)
+ kex->hash_alg,
+ kex->client_version_string,
+ kex->server_version_string,
+ sshbuf_ptr(kex->my), sshbuf_len(kex->my),
+ sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
+ server_host_key_blob, sbloblen,
+ kex->min, kex->nbits, kex->max,
+ dh_p, dh_g,
+ dh_client_pub,
+ dh_server_pub,
+ shared_secret,
+ hash, &hashlen)) != 0)
goto out;
if ((r = sshkey_verify(server_host_key, signature, slen, hash,
- hashlen, ssh->compat)) != 0)
+ hashlen, ssh->compat)) != 0)
goto out;
/* save session id */
@@ -252,21 +268,16 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
- out:
+out:
explicit_bzero(hash, sizeof(hash));
- DH_free(kex->dh);
+ sshbn_free(dh_p);
+ sshbn_free(dh_g);
+ sshbn_free(shared_secret);
+ sshbn_free(dh_client_pub);
+ sshbn_free(dh_server_pub);
+ sshdh_free(kex->dh);
kex->dh = NULL;
- if (dh_server_pub)
- BN_clear_free(dh_server_pub);
- if (kbuf) {
- explicit_bzero(kbuf, klen);
- free(kbuf);
- }
- if (shared_secret)
- BN_clear_free(shared_secret);
- sshkey_free(server_host_key);
free(server_host_key_blob);
free(signature);
return r;
}
-#endif /* WITH_OPENSSL */
diff --git a/kexgexs.c b/kexgexs.c
index cd1d620..dddc2bc 100644
--- a/kexgexs.c
+++ b/kexgexs.c
@@ -30,16 +30,8 @@
* We support only client side kerberos on Windows.
*/
-#ifdef WIN32_FIXME
- #undef GSSAPI
- #undef KRB5
-#endif
-
-#ifdef WITH_OPENSSL
-
#include /* MIN MAX */
-#include
#include
#include
#include
@@ -70,7 +62,7 @@ int
kexgex_server(struct ssh *ssh)
{
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST,
- &input_kex_dh_gex_request);
+ &input_kex_dh_gex_request);
debug("expecting SSH2_MSG_KEX_DH_GEX_REQUEST");
return 0;
}
@@ -80,14 +72,15 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
+ struct sshbn *dh_g = NULL, *dh_p = NULL;
int r;
u_int min = 0, max = 0, nbits = 0;
debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
- (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
- (r = sshpkt_get_u32(ssh, &max)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &max)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
goto out;
kex->nbits = nbits;
kex->min = min;
@@ -98,7 +91,7 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
nbits = MIN(DH_GRP_MAX, nbits);
if (kex->max < kex->min || kex->nbits < kex->min ||
- kex->max < kex->nbits) {
+ kex->max < kex->nbits) {
r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
goto out;
}
@@ -110,11 +103,16 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
+ if ((dh_p = sshdh_p(kex->dh)) == NULL ||
+ (dh_g = sshdh_g(kex->dh)) == NULL) {
+ r = SSH_ERR_INTERNAL_ERROR;
+ goto out;
+ }
debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ (r = sshpkt_put_bignum2_wrap(ssh, dh_p)) != 0 ||
+ (r = sshpkt_put_bignum2_wrap(ssh, dh_g)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
goto out;
/* Compute our exchange value in parallel with the client */
@@ -124,7 +122,9 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init);
r = 0;
- out:
+out:
+ sshbn_free(dh_g);
+ sshbn_free(dh_p);
return r;
}
@@ -133,35 +133,37 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
- BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+ struct sshbn *dh_g = NULL, *dh_p = NULL;
+ struct sshbn *dh_client_pub = NULL;
+ struct sshbn *dh_server_pub = NULL;
+ struct sshbn *shared_secret = NULL;
struct sshkey *server_host_public, *server_host_private;
- u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
+ u_char *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
- size_t sbloblen, slen;
- size_t klen = 0, hashlen;
- int kout, r;
+ size_t sbloblen, slen, hashlen;
+ int r;
if (kex->load_host_public_key == NULL ||
- kex->load_host_private_key == NULL) {
+ kex->load_host_private_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
server_host_public = kex->load_host_public_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
+ kex->hostkey_nid, ssh);
server_host_private = kex->load_host_private_key(kex->hostkey_type,
- kex->hostkey_nid, ssh);
+ kex->hostkey_nid, ssh);
if (server_host_public == NULL) {
r = SSH_ERR_NO_HOSTKEY_LOADED;
goto out;
}
/* key, cert */
- if ((dh_client_pub = BN_new()) == NULL) {
+ if ((dh_client_pub = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ if ((r = sshpkt_get_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
@@ -177,44 +179,40 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n");
#endif
- if (!dh_pub_is_valid(kex->dh, dh_client_pub)) {
+ if ((r = dh_pub_is_valid(kex->dh, dh_client_pub)) != 0) {
sshpkt_disconnect(ssh, "bad client public DH value");
- r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
-
- klen = DH_size(kex->dh);
- if ((kbuf = malloc(klen)) == NULL ||
- (shared_secret = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
+ if ((dh_server_pub = sshdh_pubkey(kex->dh)) == NULL ||
+ (dh_p = sshdh_p(kex->dh)) == NULL ||
+ (dh_g = sshdh_g(kex->dh)) == NULL) {
+ r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
- if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
- BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
- r = SSH_ERR_LIBCRYPTO_ERROR;
+ if ((r = sshdh_compute_key(kex->dh, dh_client_pub,
+ &shared_secret)) != 0)
goto out;
- }
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
- &sbloblen)) != 0)
+ &sbloblen)) != 0)
goto out;
/* calc H */
hashlen = sizeof(hash);
if ((r = kexgex_hash(
- kex->hash_alg,
- kex->client_version_string,
- kex->server_version_string,
- sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
- sshbuf_ptr(kex->my), sshbuf_len(kex->my),
- server_host_key_blob, sbloblen,
- kex->min, kex->nbits, kex->max,
- kex->dh->p, kex->dh->g,
- dh_client_pub,
- kex->dh->pub_key,
- shared_secret,
- hash, &hashlen)) != 0)
+ kex->hash_alg,
+ kex->client_version_string,
+ kex->server_version_string,
+ sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
+ sshbuf_ptr(kex->my), sshbuf_len(kex->my),
+ server_host_key_blob, sbloblen,
+ kex->min, kex->nbits, kex->max,
+ dh_p, dh_g,
+ dh_client_pub,
+ dh_server_pub,
+ shared_secret,
+ hash, &hashlen)) != 0)
goto out;
/* save session id := H */
@@ -230,34 +228,31 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
/* sign H */
if ((r = kex->sign(server_host_private, server_host_public,
- &signature, &slen, hash, hashlen, ssh->compat)) < 0)
+ &signature, &slen, hash, hashlen, ssh->compat)) < 0)
goto out;
/* destroy_sensitive_data(); */
/* send server hostkey, DH pubkey 'f' and singed H */
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 ||
- (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
- (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */
- (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
- (r = sshpkt_send(ssh)) != 0)
+ (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
+ (r = sshpkt_put_bignum2_wrap(ssh, dh_server_pub)) != 0 || /* f */
+ (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
goto out;
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
- out:
- DH_free(kex->dh);
+out:
+ explicit_bzero(hash, sizeof(hash));
+ sshbn_free(dh_p);
+ sshbn_free(dh_g);
+ sshbn_free(shared_secret);
+ sshbn_free(dh_client_pub);
+ sshbn_free(dh_server_pub);
+ sshdh_free(kex->dh);
kex->dh = NULL;
- if (dh_client_pub)
- BN_clear_free(dh_client_pub);
- if (kbuf) {
- explicit_bzero(kbuf, klen);
- free(kbuf);
- }
- if (shared_secret)
- BN_clear_free(shared_secret);
free(server_host_key_blob);
free(signature);
return r;
}
-#endif /* WITH_OPENSSL */
diff --git a/monitor.c b/monitor.c
index 9bae4e1..95d96f7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -664,8 +664,11 @@ monitor_reset_key_state(void)
int
mm_answer_moduli(int sock, Buffer *m)
{
- DH *dh;
+ struct sshdh *dh;
int min, want, max;
+ struct sshbn * dh_p = NULL;
+ struct sshbn * dh_g = NULL;
+ int ret = 0;
min = buffer_get_int(m);
want = buffer_get_int(m);
@@ -681,18 +684,25 @@ mm_answer_moduli(int sock, Buffer *m)
buffer_clear(m);
dh = choose_dh(min, want, max);
+
+
if (dh == NULL) {
buffer_put_char(m, 0);
return (0);
} else {
- /* Send first bignum */
- buffer_put_char(m, 1);
- buffer_put_bignum2(m, dh->p);
- buffer_put_bignum2(m, dh->g);
+ if ((dh_p = sshdh_p(dh)) != NULL &&
+ (dh_g = sshdh_g(dh)) != NULL) {
- DH_free(dh);
+ /* Send first bignum */
+ buffer_put_char(m, 1);
+ sshbuf_put_bignum2_wrap(m, dh_p);
+ sshbuf_put_bignum2_wrap(m, dh_g);
+ mm_request_send(sock, MONITOR_ANS_MODULI, m);
+ }
+ sshdh_free(dh);
+ sshbn_free(dh_p);
+ sshbn_free(dh_g);
}
- mm_request_send(sock, MONITOR_ANS_MODULI, m);
return (0);
}
#endif
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 851ed33..2a56fc5 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -94,6 +94,7 @@
#include "roaming.h"
#include "ssherr.h"
+#include "crypto-wrap.h"
/* Imports */
extern int compat20;
@@ -116,17 +117,17 @@ mm_log_handler(LogLevel level, const char *msg, void *ctx)
buffer_init(&log_msg);
/*
- * Placeholder for packet length. Will be filled in with the actual
- * packet length once the packet has been constucted. This saves
- * fragile math.
- */
+ * Placeholder for packet length. Will be filled in with the actual
+ * packet length once the packet has been constucted. This saves
+ * fragile math.
+ */
buffer_put_int(&log_msg, 0);
buffer_put_int(&log_msg, level);
buffer_put_cstring(&log_msg, msg);
put_u32(buffer_ptr(&log_msg), buffer_len(&log_msg) - 4);
if (atomicio(vwrite, mon->m_log_sendfd, buffer_ptr(&log_msg),
- buffer_len(&log_msg)) != buffer_len(&log_msg))
+ buffer_len(&log_msg)) != buffer_len(&log_msg))
fatal("%s: write: %s", __func__, strerror(errno));
buffer_free(&log_msg);
}
@@ -135,9 +136,9 @@ int
mm_is_monitor(void)
{
/*
- * m_pid is only set in the privileged part, and
- * points to the unprivileged child.
- */
+ * m_pid is only set in the privileged part, and
+ * points to the unprivileged child.
+ */
return (pmonitor && pmonitor->m_pid > 0);
}
@@ -150,7 +151,7 @@ mm_request_send(int sock, enum monitor_reqtype type, Buffer *m)
debug3("%s entering: type %d", __func__, type);
put_u32(buf, mlen + 1);
- buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */
+ buf[4] = (u_char)type; /* 1st byte of payload is mesg-type */
if (atomicio(vwrite, sock, buf, sizeof(buf)) != sizeof(buf))
fatal("%s: write: %s", __func__, strerror(errno));
if (atomicio(vwrite, sock, buffer_ptr(m), mlen) != mlen)
@@ -190,15 +191,15 @@ mm_request_receive_expect(int sock, enum monitor_reqtype type, Buffer *m)
rtype = buffer_get_char(m);
if (rtype != type)
fatal("%s: read: rtype %d != type %d", __func__,
- rtype, type);
+ rtype, type);
}
#ifdef WITH_OPENSSL
-DH *
-mm_choose_dh(int min, int nbits, int max)
+struct sshdh *
+ mm_choose_dh(int min, int nbits, int max)
{
- BIGNUM *p, *g;
- int success = 0;
+ struct sshbn *p, *g;
+ int r, success = 0;
Buffer m;
buffer_init(&m);
@@ -215,23 +216,22 @@ mm_choose_dh(int min, int nbits, int max)
if (success == 0)
fatal("%s: MONITOR_ANS_MODULI failed", __func__);
- if ((p = BN_new()) == NULL)
+ if ((p = sshbn_new()) == NULL || (g = sshbn_new()) == NULL)
fatal("%s: BN_new failed", __func__);
- if ((g = BN_new()) == NULL)
- fatal("%s: BN_new failed", __func__);
- buffer_get_bignum2(&m, p);
- buffer_get_bignum2(&m, g);
+ if ((r = sshbuf_get_bignum2_wrap(&m, p)) != 0 ||
+ (r = sshbuf_get_bignum2_wrap(&m, g)) != 0)
+ fatal("%s: sshbuf_get_bignum2_wrap: %s", __func__, ssh_err(r));
debug3("%s: remaining %d", __func__, buffer_len(&m));
buffer_free(&m);
- return (dh_new_group(g, p));
+ return (sshdh_new_group(g, p));
}
#endif
int
mm_key_sign(Key *key, u_char **sigp, u_int *lenp,
- const u_char *data, u_int datalen)
+ const u_char *data, u_int datalen)
{
struct kex *kex = *pmonitor->m_pkex;
Buffer m;
@@ -246,14 +246,14 @@ mm_key_sign(Key *key, u_char **sigp, u_int *lenp,
debug3("%s: waiting for MONITOR_ANS_SIGN", __func__);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SIGN, &m);
- *sigp = buffer_get_string(&m, lenp);
+ *sigp = buffer_get_string(&m, lenp);
buffer_free(&m);
return (0);
}
struct passwd *
-mm_getpwnamallow(const char *username)
+ mm_getpwnamallow(const char *username)
{
Buffer m;
struct passwd *pw;
@@ -279,12 +279,8 @@ mm_getpwnamallow(const char *username)
fatal("%s: struct passwd size mismatch", __func__);
pw->pw_name = buffer_get_string(&m, NULL);
pw->pw_passwd = buffer_get_string(&m, NULL);
-#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
pw->pw_gecos = buffer_get_string(&m, NULL);
-#endif
-#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
- pw->pw_class = buffer_get_string(&m, NULL);
-#endif
+// pw->pw_class = buffer_get_string(&m, NULL);
pw->pw_dir = buffer_get_string(&m, NULL);
pw->pw_shell = buffer_get_string(&m, NULL);
@@ -328,7 +324,7 @@ mm_auth2_read_banner(void)
buffer_clear(&m);
mm_request_receive_expect(pmonitor->m_recvfd,
- MONITOR_ANS_AUTH2_READ_BANNER, &m);
+ MONITOR_ANS_AUTH2_READ_BANNER, &m);
banner = buffer_get_string(&m, NULL);
buffer_free(&m);
@@ -379,7 +375,7 @@ mm_auth_password(Authctxt *authctxt, char *password)
buffer_free(&m);
debug3("%s: user %sauthenticated",
- __func__, authenticated ? "" : "not ");
+ __func__, authenticated ? "" : "not ");
return (authenticated);
}
@@ -387,19 +383,19 @@ int
mm_user_key_allowed(struct passwd *pw, Key *key, int pubkey_auth_attempt)
{
return (mm_key_allowed(MM_USERKEY, NULL, NULL, key,
- pubkey_auth_attempt));
+ pubkey_auth_attempt));
}
int
mm_hostbased_key_allowed(struct passwd *pw, char *user, char *host,
- Key *key)
+ Key *key)
{
return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0));
}
int
mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user,
- char *host, Key *key)
+ char *host, Key *key)
{
int ret;
@@ -411,7 +407,7 @@ mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user,
int
mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key,
- int pubkey_auth_attempt)
+ int pubkey_auth_attempt)
{
Buffer m;
u_char *blob;
@@ -450,10 +446,10 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key,
}
/*
- * This key verify needs to send the key type along, because the
- * privileged parent makes the decision if the key is allowed
- * for authentication.
- */
+* This key verify needs to send the key type along, because the
+* privileged parent makes the decision if the key is allowed
+* for authentication.
+*/
int
mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
@@ -498,7 +494,7 @@ mm_send_keystate(struct monitor *monitor)
fatal("%s: sshbuf_new failed", __func__);
if ((r = ssh_packet_get_state(ssh, m)) != 0)
fatal("%s: get_state failed: %s",
- __func__, ssh_err(r));
+ __func__, ssh_err(r));
mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, m);
debug3("%s: Finished sending state", __func__);
sshbuf_free(m);
@@ -513,7 +509,7 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
/* Kludge: ensure there are fds free to receive the pty/tty */
if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
- (tmp2 = dup(pmonitor->m_recvfd)) == -1) {
+ (tmp2 = dup(pmonitor->m_recvfd)) == -1) {
error("%s: cannot allocate fds for pty", __func__);
if (tmp1 > 0)
close(tmp1);
@@ -547,7 +543,7 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
free(msg);
if ((*ptyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1 ||
- (*ttyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1)
+ (*ttyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1)
fatal("%s: receive fds failed", __func__);
/* Success */
@@ -569,143 +565,12 @@ mm_session_pty_cleanup2(Session *s)
/* closed dup'ed master */
if (s->ptymaster != -1 && close(s->ptymaster) < 0)
error("close(s->ptymaster/%d): %s",
- s->ptymaster, strerror(errno));
+ s->ptymaster, strerror(errno));
/* unlink pty from session */
s->ttyfd = -1;
}
-#ifdef USE_PAM
-void
-mm_start_pam(Authctxt *authctxt)
-{
- Buffer m;
-
- debug3("%s entering", __func__);
- if (!options.use_pam)
- fatal("UsePAM=no, but ended up in %s anyway", __func__);
-
- buffer_init(&m);
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_START, &m);
-
- buffer_free(&m);
-}
-
-u_int
-mm_do_pam_account(void)
-{
- Buffer m;
- u_int ret;
- char *msg;
-
- debug3("%s entering", __func__);
- if (!options.use_pam)
- fatal("UsePAM=no, but ended up in %s anyway", __func__);
-
- buffer_init(&m);
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_ACCOUNT, &m);
-
- mm_request_receive_expect(pmonitor->m_recvfd,
- MONITOR_ANS_PAM_ACCOUNT, &m);
- ret = buffer_get_int(&m);
- msg = buffer_get_string(&m, NULL);
- buffer_append(&loginmsg, msg, strlen(msg));
- free(msg);
-
- buffer_free(&m);
-
- debug3("%s returning %d", __func__, ret);
-
- return (ret);
-}
-
-void *
-mm_sshpam_init_ctx(Authctxt *authctxt)
-{
- Buffer m;
- int success;
-
- debug3("%s", __func__);
- buffer_init(&m);
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, &m);
- debug3("%s: waiting for MONITOR_ANS_PAM_INIT_CTX", __func__);
- mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_INIT_CTX, &m);
- success = buffer_get_int(&m);
- if (success == 0) {
- debug3("%s: pam_init_ctx failed", __func__);
- buffer_free(&m);
- return (NULL);
- }
- buffer_free(&m);
- return (authctxt);
-}
-
-int
-mm_sshpam_query(void *ctx, char **name, char **info,
- u_int *num, char ***prompts, u_int **echo_on)
-{
- Buffer m;
- u_int i;
- int ret;
-
- debug3("%s", __func__);
- buffer_init(&m);
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_QUERY, &m);
- debug3("%s: waiting for MONITOR_ANS_PAM_QUERY", __func__);
- mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_QUERY, &m);
- ret = buffer_get_int(&m);
- debug3("%s: pam_query returned %d", __func__, ret);
- *name = buffer_get_string(&m, NULL);
- *info = buffer_get_string(&m, NULL);
- *num = buffer_get_int(&m);
- if (*num > PAM_MAX_NUM_MSG)
- fatal("%s: recieved %u PAM messages, expected <= %u",
- __func__, *num, PAM_MAX_NUM_MSG);
- *prompts = xcalloc((*num + 1), sizeof(char *));
- *echo_on = xcalloc((*num + 1), sizeof(u_int));
- for (i = 0; i < *num; ++i) {
- (*prompts)[i] = buffer_get_string(&m, NULL);
- (*echo_on)[i] = buffer_get_int(&m);
- }
- buffer_free(&m);
- return (ret);
-}
-
-int
-mm_sshpam_respond(void *ctx, u_int num, char **resp)
-{
- Buffer m;
- u_int i;
- int ret;
-
- debug3("%s", __func__);
- buffer_init(&m);
- buffer_put_int(&m, num);
- for (i = 0; i < num; ++i)
- buffer_put_cstring(&m, resp[i]);
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_RESPOND, &m);
- debug3("%s: waiting for MONITOR_ANS_PAM_RESPOND", __func__);
- mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_RESPOND, &m);
- ret = buffer_get_int(&m);
- debug3("%s: pam_respond returned %d", __func__, ret);
- buffer_free(&m);
- return (ret);
-}
-
-void
-mm_sshpam_free_ctx(void *ctxtp)
-{
- Buffer m;
-
- debug3("%s", __func__);
- buffer_init(&m);
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_FREE_CTX, &m);
- debug3("%s: waiting for MONITOR_ANS_PAM_FREE_CTX", __func__);
- mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_FREE_CTX, &m);
- buffer_free(&m);
-}
-#endif /* USE_PAM */
-
/* Request process termination */
void
@@ -742,7 +607,7 @@ mm_ssh1_session_key(BIGNUM *num)
static void
mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
- char ***prompts, u_int **echo_on)
+ char ***prompts, u_int **echo_on)
{
*name = xstrdup("");
*infotxt = xstrdup("");
@@ -754,7 +619,7 @@ mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
int
mm_bsdauth_query(void *ctx, char **name, char **infotxt,
- u_int *numprompts, char ***prompts, u_int **echo_on)
+ u_int *numprompts, char ***prompts, u_int **echo_on)
{
Buffer m;
u_int success;
@@ -766,7 +631,7 @@ mm_bsdauth_query(void *ctx, char **name, char **infotxt,
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, &m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_BSDAUTHQUERY,
- &m);
+ &m);
success = buffer_get_int(&m);
if (success == 0) {
debug3("%s: no challenge", __func__);
@@ -775,7 +640,7 @@ mm_bsdauth_query(void *ctx, char **name, char **infotxt,
}
/* Get the challenge, and format the response */
- challenge = buffer_get_string(&m, NULL);
+ challenge = buffer_get_string(&m, NULL);
buffer_free(&m);
mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
@@ -801,7 +666,7 @@ mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, &m);
mm_request_receive_expect(pmonitor->m_recvfd,
- MONITOR_ANS_BSDAUTHRESPOND, &m);
+ MONITOR_ANS_BSDAUTHRESPOND, &m);
authok = buffer_get_int(&m);
buffer_free(&m);
@@ -809,66 +674,6 @@ mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
return ((authok == 0) ? -1 : 0);
}
-#ifdef SKEY
-int
-mm_skey_query(void *ctx, char **name, char **infotxt,
- u_int *numprompts, char ***prompts, u_int **echo_on)
-{
- Buffer m;
- u_int success;
- char *challenge;
-
- debug3("%s: entering", __func__);
-
- buffer_init(&m);
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYQUERY, &m);
-
- mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SKEYQUERY,
- &m);
- success = buffer_get_int(&m);
- if (success == 0) {
- debug3("%s: no challenge", __func__);
- buffer_free(&m);
- return (-1);
- }
-
- /* Get the challenge, and format the response */
- challenge = buffer_get_string(&m, NULL);
- buffer_free(&m);
-
- debug3("%s: received challenge: %s", __func__, challenge);
-
- mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
-
- xasprintf(*prompts, "%s%s", challenge, SKEY_PROMPT);
- free(challenge);
-
- return (0);
-}
-
-int
-mm_skey_respond(void *ctx, u_int numresponses, char **responses)
-{
- Buffer m;
- int authok;
-
- debug3("%s: entering", __func__);
- if (numresponses != 1)
- return (-1);
-
- buffer_init(&m);
- buffer_put_cstring(&m, responses[0]);
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYRESPOND, &m);
-
- mm_request_receive_expect(pmonitor->m_recvfd,
- MONITOR_ANS_SKEYRESPOND, &m);
-
- authok = buffer_get_int(&m);
- buffer_free(&m);
-
- return ((authok == 0) ? -1 : 0);
-}
-#endif /* SKEY */
void
mm_ssh1_session_id(u_char session_id[16])
@@ -984,36 +789,6 @@ mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16])
}
#endif
-#ifdef SSH_AUDIT_EVENTS
-void
-mm_audit_event(ssh_audit_event_t event)
-{
- Buffer m;
-
- debug3("%s entering", __func__);
-
- buffer_init(&m);
- buffer_put_int(&m, event);
-
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_EVENT, &m);
- buffer_free(&m);
-}
-
-void
-mm_audit_run_command(const char *command)
-{
- Buffer m;
-
- debug3("%s entering command %s", __func__, command);
-
- buffer_init(&m);
- buffer_put_cstring(&m, command);
-
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m);
- buffer_free(&m);
-}
-#endif /* SSH_AUDIT_EVENTS */
-
#ifdef GSSAPI
OM_uint32
mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid)
@@ -1038,7 +813,7 @@ mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid)
OM_uint32
mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
- gss_buffer_desc *out, OM_uint32 *flags)
+ gss_buffer_desc *out, OM_uint32 *flags)
{
Buffer m;
OM_uint32 major;
@@ -1073,7 +848,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSCHECKMIC, &m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSCHECKMIC,
- &m);
+ &m);
major = buffer_get_int(&m);
buffer_free(&m);
@@ -1090,12 +865,12 @@ mm_ssh_gssapi_userok(char *user)
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
- &m);
+ &m);
authenticated = buffer_get_int(&m);
buffer_free(&m);
- debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
+ debug3("%s: user %sauthenticated", __func__, authenticated ? "" : "not ");
return (authenticated);
}
#endif /* GSSAPI */
diff --git a/monitor_wrap.h b/monitor_wrap.h
index de4a08f..95741f7 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -39,7 +39,7 @@ struct Authctxt;
void mm_log_handler(LogLevel, const char *, void *);
int mm_is_monitor(void);
-DH *mm_choose_dh(int, int, int);
+struct sshdh *mm_choose_dh(int, int, int);
int mm_key_sign(Key *, u_char **, u_int *, const u_char *, u_int);
void mm_inform_authserv(char *, char *);
struct passwd *mm_getpwnamallow(const char *);
diff --git a/openssl-bn.c b/openssl-bn.c
new file mode 100644
index 0000000..b80ef1e
--- /dev/null
+++ b/openssl-bn.c
@@ -0,0 +1,214 @@
+/*
+* Copyright (c) 2015 Damien Miller
+*
+* Permission to use, copy, modify, and distribute this software for any
+* purpose with or without fee is hereby granted, provided that the above
+* copyright notice and this permission notice appear in all copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include
+
+
+#include
+#include
+#include
+#include
+#include
+
+
+#include
+
+
+#include "sshbuf.h"
+#include "packet.h"
+#include "ssherr.h"
+#include "crypto-wrap.h"
+
+struct sshbn {
+ BIGNUM *bn;
+};
+
+
+static struct sshbn *
+bnwrap(BIGNUM *bn)
+{
+ struct sshbn *ret;
+
+ if (bn == NULL)
+ return NULL;
+
+ if ((ret = calloc(1, sizeof(*ret))) == NULL)
+ return NULL;
+ if ((ret->bn = BN_dup(bn)) == NULL) {
+ free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+struct sshbn *
+ sshbn_new(void)
+{
+ return bnwrap(BN_new());
+}
+
+void
+sshbn_free(struct sshbn *bn)
+{
+ if (bn != NULL) {
+ if (bn->bn != NULL)
+ BN_clear_free(bn->bn);
+ explicit_bzero(bn, sizeof(*bn));
+ free(bn);
+ }
+}
+
+int
+sshbn_from(const void *d, size_t l, struct sshbn **retp)
+{
+ struct sshbn *ret;
+ const u_char *dd = (const u_char *)d;
+
+ *retp = NULL;
+ if (l > INT_MAX)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((ret = sshbn_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if (BN_bin2bn(dd, (int)l, ret->bn) == NULL) {
+ sshbn_free(ret);
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ }
+ *retp = ret;
+ return 0;
+}
+
+int
+sshbn_from_hex(const char *hex, struct sshbn **retp)
+{
+ struct sshbn *ret;
+
+ *retp = NULL;
+ if ((ret = sshbn_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+
+ if (BN_hex2bn(&ret->bn, hex) <= 0) {
+ sshbn_free(ret);
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ }
+ *retp = ret;
+ return 0;
+}
+
+int sshbn_to(const struct sshbn *a, unsigned char *to)
+{
+
+ return BN_bn2bin(sshbn_bignum(a), to);
+}
+
+size_t
+sshbn_bytes(const struct sshbn *bn)
+{
+ int bytes = BN_num_bytes(bn->bn);
+
+ return bytes < 0 ? 0 : (size_t)bytes;
+}
+
+size_t
+sshbn_bits(const struct sshbn *bn)
+{
+ int bits = BN_num_bits(bn->bn);
+
+ return bits < 0 ? 0 : (size_t)bits;
+}
+
+const struct sshbn *
+sshbn_value_0(void)
+{
+ static struct sshbn *ret;
+
+ if (ret == NULL)
+ sshbn_from_hex("0", &ret);
+ return ret;
+}
+
+const struct sshbn *
+sshbn_value_1(void)
+{
+ static struct sshbn *ret;
+
+ if (ret == NULL)
+ sshbn_from_hex("1", &ret);
+ return ret;
+}
+
+
+
+int
+sshbn_cmp(const struct sshbn *a, const struct sshbn *b)
+{
+ return BN_cmp(a->bn, b->bn);
+}
+
+int
+sshbn_sub(struct sshbn *r, const struct sshbn *a, const struct sshbn *b)
+{
+ if (BN_sub(r->bn, a->bn, b->bn) != 1)
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ return 0;
+}
+
+int
+sshbn_is_bit_set(const struct sshbn *bn, size_t i)
+{
+ if (i > INT_MAX)
+ return 0;
+ return BN_is_bit_set(bn->bn, (int)i);
+}
+
+/* XXX move to sshbuf.h */
+int
+sshbuf_get_bignum2_wrap(struct sshbuf *buf, struct sshbn *bn)
+{
+ return sshbuf_get_bignum2(buf, bn->bn);
+}
+
+int
+sshbuf_put_bignum2_wrap(struct sshbuf *buf, const struct sshbn *bn)
+{
+ return sshbuf_put_bignum2(buf, bn->bn);
+}
+
+int
+sshpkt_get_bignum2_wrap(struct ssh *ssh, struct sshbn *bn)
+{
+ return sshpkt_get_bignum2(ssh, bn->bn);
+}
+
+int
+sshpkt_put_bignum2_wrap(struct ssh *ssh, const struct sshbn *bn)
+{
+ return sshpkt_put_bignum2(ssh, bn->bn);
+}
+
+/* bridge to unwrapped OpenSSL APIs; XXX remove later */
+BIGNUM *
+sshbn_bignum(struct sshbn *bn)
+{
+ return bn->bn;
+}
+
+
+struct sshbn *
+ sshbn_from_bignum(BIGNUM *bn)
+{
+ return bnwrap(bn);
+}
+
diff --git a/openssl-dh.c b/openssl-dh.c
new file mode 100644
index 0000000..319f92d
--- /dev/null
+++ b/openssl-dh.c
@@ -0,0 +1,199 @@
+/*
+* Copyright (c) 2015 Damien Miller
+*
+* Permission to use, copy, modify, and distribute this software for any
+* purpose with or without fee is hereby granted, provided that the above
+* copyright notice and this permission notice appear in all copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include
+
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "sshbuf.h"
+#include "packet.h"
+#include "ssherr.h"
+#include "crypto-wrap.h"
+
+struct sshdh {
+ DH *dh;
+};
+struct sshbn {
+ BIGNUM *bn;
+};
+
+
+static struct sshbn *
+bnwrap(BIGNUM *bn)
+{
+ struct sshbn *ret;
+
+ if (bn == NULL)
+ return NULL;
+
+ if ((ret = calloc(1, sizeof(*ret))) == NULL)
+ return NULL;
+ if ((ret->bn = BN_dup(bn)) == NULL) {
+ free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+/* DH wrappers */
+
+struct sshdh *
+ sshdh_new(void)
+{
+ struct sshdh *ret;
+
+ if ((ret = calloc(1, sizeof(*ret))) == NULL)
+ return NULL;
+ if ((ret->dh = DH_new()) == NULL) {
+ free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+void
+sshdh_free(struct sshdh *dh)
+{
+ if (dh != NULL) {
+ if (dh->dh != NULL)
+ DH_free(dh->dh);
+ explicit_bzero(dh, sizeof(*dh));
+ free(dh);
+ }
+}
+
+struct sshbn *
+ sshdh_pubkey(struct sshdh *dh)
+{
+ return bnwrap(dh->dh->pub_key);
+}
+
+struct sshbn *
+ sshdh_p(struct sshdh *dh)
+{
+ return bnwrap(dh->dh->p);
+}
+
+struct sshbn *
+ sshdh_g(struct sshdh *dh)
+{
+ return bnwrap(dh->dh->g);
+}
+
+void
+sshdh_dump(struct sshdh *dh)
+{
+ DHparams_print_fp(stderr, dh->dh);
+ fprintf(stderr, "pub= ");
+ BN_print_fp(stderr, dh->dh->pub_key);
+ fprintf(stderr, "\n");
+}
+
+// XXX needed?
+size_t
+sshdh_shared_key_size(struct sshdh *dh)
+{
+ int sz;
+
+ if (dh == NULL || dh->dh == NULL || (sz = DH_size(dh->dh)) < 0)
+ return 0;
+ return (size_t)sz;
+}
+
+int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey,
+struct sshbn **shared_secretp)
+{
+ u_char *sbuf;
+ int r, slen;
+
+ *shared_secretp = NULL;
+ if ((slen = DH_size(dh->dh)) <= 0)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((sbuf = calloc(1, slen)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = DH_compute_key(sbuf, pubkey->bn, dh->dh)) < 0 ||
+ r != slen) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if ((r = sshbn_from(sbuf, slen, shared_secretp)) != 0)
+ goto out;
+ /* success */
+ r = 0;
+out:
+ explicit_bzero(sbuf, slen);
+ free(sbuf);
+ return r;
+}
+
+int
+sshdh_generate(struct sshdh *dh, size_t len)
+{
+ if (len > INT_MAX)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if (len != 0)
+ dh->dh->length = (int)len;
+ if (DH_generate_key(dh->dh) != 1)
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ return 0;
+}
+
+int
+sshdh_new_group_hex(const char *gen, const char *modulus, struct sshdh **dhp)
+{
+ struct sshdh *ret;
+
+ *dhp = NULL;
+ if ((ret = sshdh_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if (BN_hex2bn(&ret->dh->p, modulus) == 0 ||
+ BN_hex2bn(&ret->dh->g, gen) == 0) {
+ sshdh_free(ret);
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ }
+ *dhp = ret;
+ return 0;
+}
+
+/* XXX transfers ownership of gen, modulus */
+struct sshdh *
+ sshdh_new_group(struct sshbn *gen, struct sshbn *modulus)
+{
+ struct sshdh *dh;
+
+ if ((dh = sshdh_new()) == NULL)
+ return NULL;
+ dh->dh->p = modulus->bn;
+ dh->dh->g = gen->bn;
+ modulus->bn = gen->bn = NULL;
+ sshbn_free(gen);
+ sshbn_free(modulus);
+ return (dh);
+}
+
+
+DH *sshdh_dh(struct sshdh *dh)
+{
+ return dh->dh;
+}
\ No newline at end of file
diff --git a/sshconnect2.c b/sshconnect2.c
index d7ede03..22f3ab5 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -76,11 +76,7 @@
#include "ssh-gss.h"
#endif
-#ifdef USE_MSCNG
-/* CNG KEX imports */
-int cng_kexgex_client(struct ssh *ssh);
-int cng_kexdh_client(struct ssh *ssh);
-#endif
+
/* import */
extern char *client_version_string;
@@ -217,22 +213,16 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
if ((r = kex_setup(active_state, myproposal)) != 0)
fatal("kex_setup: %s", ssh_err(r));
kex = active_state->kex;
-#ifdef WITH_OPENSSL
-#ifdef USE_MSCNG
- kex->kex[KEX_DH_GRP1_SHA1] = cng_kexdh_client;
- kex->kex[KEX_DH_GRP14_SHA1] = cng_kexdh_client;
- kex->kex[KEX_DH_GEX_SHA1] = cng_kexgex_client;
- kex->kex[KEX_DH_GEX_SHA256] = cng_kexgex_client;
-#else
+
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
-#endif
+
# ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
# endif
-#endif
+
kex->kex[KEX_C25519_SHA256] = kexc25519_client;
kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string;
diff --git a/sshd.c b/sshd.c
index 1075a2b..250b973 100644
--- a/sshd.c
+++ b/sshd.c
@@ -145,11 +145,7 @@
#define O_NOCTTY 0
#endif
-#ifdef USE_MSCNG
- /* CNG KEX imports */
-int cng_kexgex_server(struct ssh *ssh);
-int cng_kexdh_server(struct ssh *ssh);
-#endif
+
/* Re-exec fds */
#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
@@ -3384,22 +3380,17 @@ do_ssh2_kex(void)
if ((r = kex_setup(active_state, myproposal)) != 0)
fatal("kex_setup: %s", ssh_err(r));
kex = active_state->kex;
-#ifdef WITH_OPENSSL
-#ifdef USE_MSCNG
- kex->kex[KEX_DH_GRP1_SHA1] = cng_kexdh_server;
- kex->kex[KEX_DH_GRP14_SHA1] = cng_kexdh_server;
- kex->kex[KEX_DH_GEX_SHA1] = cng_kexgex_server;
- kex->kex[KEX_DH_GEX_SHA256] = cng_kexgex_server;
-#else
+
+
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
-#endif
+
# ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
# endif
-#endif
+
kex->kex[KEX_C25519_SHA256] = kexc25519_server;
kex->server = 1;
kex->client_version_string=client_version_string;