mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 20:30:38 +09:00
Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
928 lines
32 KiB
C
928 lines
32 KiB
C
/*
|
|
* dh.c - Diffie-Helman algorithm code against SSH 2
|
|
*
|
|
* This file is part of the SSH Library
|
|
*
|
|
* Copyright (c) 2003-2018 by Aris Adamantiadis
|
|
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
|
|
* Copyright (c) 2012 by Dmitriy Kuznetsov <dk@yandex.ru>
|
|
*
|
|
* The SSH Library is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* The SSH Library is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
* License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with the SSH Library; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
* MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "libssh/priv.h"
|
|
#include "libssh/crypto.h"
|
|
#include "libssh/buffer.h"
|
|
#include "libssh/session.h"
|
|
#include "libssh/misc.h"
|
|
#include "libssh/dh.h"
|
|
#include "libssh/ssh2.h"
|
|
#include "libssh/pki.h"
|
|
#include "libssh/bignum.h"
|
|
|
|
static unsigned char p_group1_value[] = {
|
|
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};
|
|
#define P_GROUP1_LEN 128 /* Size in bytes of the p number */
|
|
|
|
|
|
static unsigned char p_group14_value[] = {
|
|
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};
|
|
|
|
#define P_GROUP14_LEN 256 /* Size in bytes of the p number for group 14 */
|
|
|
|
static unsigned char p_group16_value[] = {
|
|
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, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D,
|
|
0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
|
|
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57,
|
|
0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
|
|
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0,
|
|
0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
|
|
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73,
|
|
0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
|
|
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0,
|
|
0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
|
|
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20,
|
|
0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
|
|
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18,
|
|
0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
|
|
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB,
|
|
0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
|
|
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F,
|
|
0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
|
|
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76,
|
|
0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
|
|
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC,
|
|
0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
|
|
|
#define P_GROUP16_LEN 512 /* Size in bytes of the p number for group 16 */
|
|
|
|
static unsigned char p_group18_value[] = {
|
|
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, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D,
|
|
0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
|
|
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57,
|
|
0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
|
|
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0,
|
|
0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
|
|
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73,
|
|
0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
|
|
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0,
|
|
0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
|
|
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20,
|
|
0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
|
|
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18,
|
|
0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
|
|
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB,
|
|
0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
|
|
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F,
|
|
0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
|
|
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76,
|
|
0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
|
|
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC,
|
|
0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
|
|
0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, 0xC1, 0xD4, 0xDC, 0xB2,
|
|
0x60, 0x26, 0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
|
|
0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38, 0x2F,
|
|
0x41, 0x30, 0x01, 0xAE, 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
|
|
0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, 0xDA, 0x3E, 0xDB, 0xEB,
|
|
0xCF, 0x9B, 0x14, 0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
|
|
0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51,
|
|
0x2B, 0xD7, 0xAF, 0x42, 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
|
|
0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, 0xF0, 0x32, 0xEA, 0x15,
|
|
0xD1, 0x72, 0x1D, 0x03, 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
|
|
0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31,
|
|
0x90, 0x0B, 0x1C, 0x9E, 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
|
|
0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, 0x0F, 0x1D, 0x45, 0xB7,
|
|
0xFF, 0x58, 0x5A, 0xC5, 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
|
|
0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, 0x14, 0xCC, 0x5E, 0xD2,
|
|
0x0F, 0x80, 0x37, 0xE0, 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
|
|
0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, 0xF5, 0x50, 0xAA, 0x3D,
|
|
0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
|
|
0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, 0x38, 0x7F, 0xE8, 0xD7,
|
|
0x6E, 0x3C, 0x04, 0x68, 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
|
|
0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, 0xE6, 0x94, 0xF9, 0x1E,
|
|
0x6D, 0xBE, 0x11, 0x59, 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4,
|
|
0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, 0xD8, 0xBE, 0xC4, 0xD0,
|
|
0x73, 0xB9, 0x31, 0xBA, 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00,
|
|
0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, 0x25, 0x76, 0xF6, 0x93,
|
|
0x6B, 0xA4, 0x24, 0x66, 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68,
|
|
0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, 0x23, 0x8F, 0x16, 0xCB,
|
|
0xE3, 0x9D, 0x65, 0x2D, 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9,
|
|
0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, 0x13, 0xEB, 0x57, 0xA8,
|
|
0x1A, 0x23, 0xF0, 0xC7, 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B,
|
|
0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, 0xFA, 0x9D, 0x4B, 0x7F,
|
|
0xA2, 0xC0, 0x87, 0xE8, 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A,
|
|
0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, 0x6D, 0x2A, 0x13, 0xF8,
|
|
0x3F, 0x44, 0xF8, 0x2D, 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36,
|
|
0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, 0x64, 0xF3, 0x1C, 0xC5,
|
|
0x08, 0x46, 0x85, 0x1D, 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1,
|
|
0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, 0xFA, 0xF3, 0x6B, 0xC3,
|
|
0x1E, 0xCF, 0xA2, 0x68, 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92,
|
|
0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, 0x88, 0x9A, 0x00, 0x2E,
|
|
0xD5, 0xEE, 0x38, 0x2B, 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47,
|
|
0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, 0x9E, 0x30, 0x50, 0xE2,
|
|
0x76, 0x56, 0x94, 0xDF, 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
|
|
0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF};
|
|
|
|
#define P_GROUP18_LEN 1024 /* Size in bytes of the p number for group 18 */
|
|
/*
|
|
* How many bits of security we want for fast DH. DH private key size must be
|
|
* twice that size.
|
|
*/
|
|
#define DH_SECURITY_BITS 512
|
|
|
|
static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */
|
|
static bignum g;
|
|
static bignum p_group1;
|
|
static bignum p_group14;
|
|
static bignum p_group16;
|
|
static bignum p_group18;
|
|
static int dh_crypto_initialized;
|
|
|
|
/**
|
|
* @internal
|
|
* @brief Initialize global constants used in DH key agreement
|
|
* @return SSH_OK on success, SSH_ERROR otherwise.
|
|
*/
|
|
int ssh_dh_init(void)
|
|
{
|
|
int rc;
|
|
if (dh_crypto_initialized) {
|
|
return SSH_OK;
|
|
}
|
|
|
|
g = bignum_new();
|
|
if (g == NULL) {
|
|
goto error;
|
|
}
|
|
rc = bignum_set_word(g, g_int);
|
|
if (rc != 1) {
|
|
goto error;
|
|
}
|
|
|
|
#if defined(HAVE_LIBMBEDCRYPTO)
|
|
/* FIXME */
|
|
p_group1 = bignum_new();
|
|
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
|
|
|
|
p_group14 = bignum_new();
|
|
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
|
|
|
|
p_group16 = bignum_new();
|
|
bignum_bin2bn(p_group16_value, P_GROUP16_LEN, p_group16);
|
|
|
|
p_group18 = bignum_new();
|
|
bignum_bin2bn(p_group18_value, P_GROUP18_LEN, p_group18);
|
|
#else
|
|
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, &p_group1);
|
|
if (p_group1 == NULL) {
|
|
goto error;
|
|
}
|
|
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14);
|
|
if (p_group14 == NULL) {
|
|
goto error;
|
|
}
|
|
bignum_bin2bn(p_group16_value, P_GROUP16_LEN, &p_group16);
|
|
if (p_group16 == NULL) {
|
|
goto error;
|
|
}
|
|
bignum_bin2bn(p_group18_value, P_GROUP18_LEN, &p_group18);
|
|
if (p_group18 == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
#endif
|
|
|
|
dh_crypto_initialized = 1;
|
|
|
|
return 0;
|
|
error:
|
|
bignum_safe_free(g);
|
|
bignum_safe_free(p_group1);
|
|
bignum_safe_free(p_group14);
|
|
bignum_safe_free(p_group16);
|
|
return SSH_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* @brief Finalize and free global constants used in DH key agreement
|
|
*/
|
|
void ssh_dh_finalize(void)
|
|
{
|
|
if (!dh_crypto_initialized) {
|
|
return;
|
|
}
|
|
|
|
bignum_safe_free(g);
|
|
bignum_safe_free(p_group1);
|
|
bignum_safe_free(p_group14);
|
|
bignum_safe_free(p_group16);
|
|
bignum_safe_free(p_group18);
|
|
|
|
dh_crypto_initialized = 0;
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* @brief allocate and initialize ephemeral values used in dh kex
|
|
*/
|
|
int ssh_dh_init_common(ssh_session session){
|
|
struct ssh_crypto_struct *crypto=session->next_crypto;
|
|
crypto->x = bignum_new();
|
|
crypto->y = bignum_new();
|
|
crypto->e = NULL;
|
|
crypto->f = NULL;
|
|
crypto->k = bignum_new();
|
|
crypto->g = NULL;
|
|
crypto->p = NULL;
|
|
crypto->dh_group_is_mutable = 0;
|
|
switch(session->next_crypto->kex_type) {
|
|
case SSH_KEX_DH_GROUP1_SHA1:
|
|
session->next_crypto->p = p_group1;
|
|
session->next_crypto->g = g;
|
|
session->next_crypto->dh_group_is_mutable = 0;
|
|
break;
|
|
case SSH_KEX_DH_GROUP14_SHA1:
|
|
session->next_crypto->p = p_group14;
|
|
session->next_crypto->g = g;
|
|
session->next_crypto->dh_group_is_mutable = 0;
|
|
break;
|
|
case SSH_KEX_DH_GROUP16_SHA512:
|
|
session->next_crypto->p = p_group16;
|
|
session->next_crypto->g = g;
|
|
session->next_crypto->dh_group_is_mutable = 0;
|
|
break;
|
|
case SSH_KEX_DH_GROUP18_SHA512:
|
|
session->next_crypto->p = p_group18;
|
|
session->next_crypto->g = g;
|
|
session->next_crypto->dh_group_is_mutable = 0;
|
|
break;
|
|
default:
|
|
/* fall through */
|
|
break;
|
|
}
|
|
if (crypto->x == NULL || crypto->y == NULL || crypto->k == NULL){
|
|
bignum_safe_free(crypto->k);
|
|
bignum_safe_free(crypto->y);
|
|
bignum_safe_free(crypto->x);
|
|
ssh_set_error_oom(session);
|
|
return SSH_ERROR;
|
|
} else {
|
|
return SSH_OK;
|
|
}
|
|
}
|
|
|
|
void ssh_dh_cleanup(struct ssh_crypto_struct *crypto){
|
|
bignum_safe_free(crypto->x);
|
|
bignum_safe_free(crypto->y);
|
|
bignum_safe_free(crypto->e);
|
|
bignum_safe_free(crypto->f);
|
|
if (crypto->dh_group_is_mutable){
|
|
bignum_safe_free(crypto->p);
|
|
bignum_safe_free(crypto->g);
|
|
}
|
|
}
|
|
|
|
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
|
|
{
|
|
return ssh_pki_import_pubkey_blob(pubkey_blob,
|
|
&session->next_crypto->server_pubkey);
|
|
|
|
}
|
|
|
|
#ifdef DEBUG_CRYPTO
|
|
static void ssh_dh_debug(ssh_session session)
|
|
{
|
|
ssh_print_bignum("p", session->next_crypto->p);
|
|
ssh_print_bignum("g", session->next_crypto->g);
|
|
ssh_print_bignum("x", session->next_crypto->x);
|
|
ssh_print_bignum("y", session->next_crypto->y);
|
|
ssh_print_bignum("e", session->next_crypto->e);
|
|
ssh_print_bignum("f", session->next_crypto->f);
|
|
|
|
ssh_print_hexa("Session server cookie",
|
|
session->next_crypto->server_kex.cookie, 16);
|
|
ssh_print_hexa("Session client cookie",
|
|
session->next_crypto->client_kex.cookie, 16);
|
|
ssh_print_bignum("k", session->next_crypto->k);
|
|
}
|
|
#else
|
|
#define ssh_dh_debug(session)
|
|
#endif
|
|
|
|
/** @internal
|
|
* @brief generates a secret DH parameter of at least DH_SECURITY_BITS
|
|
* security.
|
|
* @param[out] dest preallocated bignum where to store the parameter
|
|
* @return SSH_OK on success, SSH_ERROR on error
|
|
*/
|
|
int ssh_dh_generate_secret(ssh_session session, bignum dest)
|
|
{
|
|
bignum tmp = NULL;
|
|
bignum_CTX ctx = NULL;
|
|
int rc = 0;
|
|
int bits = 0;
|
|
int p_bits = 0;
|
|
|
|
ctx = bignum_ctx_new();
|
|
if (bignum_ctx_invalid(ctx)){
|
|
goto error;
|
|
}
|
|
tmp = bignum_new();
|
|
if (tmp == NULL) {
|
|
goto error;
|
|
}
|
|
p_bits = bignum_num_bits(session->next_crypto->p);
|
|
/* we need at most DH_SECURITY_BITS */
|
|
bits = MIN(DH_SECURITY_BITS * 2, p_bits);
|
|
/* ensure we're not too close of p so rnd()%p stays uniform */
|
|
if (bits <= p_bits && bits + 64 > p_bits) {
|
|
bits += 64;
|
|
}
|
|
rc = bignum_rand(tmp, bits);
|
|
if (rc != 1) {
|
|
goto error;
|
|
}
|
|
rc = bignum_mod(dest, tmp, session->next_crypto->p, ctx);
|
|
if (rc != 1) {
|
|
goto error;
|
|
}
|
|
bignum_safe_free(tmp);
|
|
bignum_ctx_free(ctx);
|
|
return SSH_OK;
|
|
error:
|
|
ssh_set_error_oom(session);
|
|
bignum_safe_free(tmp);
|
|
bignum_ctx_free(ctx);
|
|
return SSH_ERROR;
|
|
}
|
|
|
|
int ssh_dh_build_k(ssh_session session)
|
|
{
|
|
int rc;
|
|
bignum_CTX ctx = bignum_ctx_new();
|
|
if (bignum_ctx_invalid(ctx)) {
|
|
return -1;
|
|
}
|
|
|
|
/* the server and clients don't use the same numbers */
|
|
if (session->client) {
|
|
rc = bignum_mod_exp(session->next_crypto->k,
|
|
session->next_crypto->f,
|
|
session->next_crypto->x,
|
|
session->next_crypto->p,
|
|
ctx);
|
|
} else {
|
|
rc = bignum_mod_exp(session->next_crypto->k,
|
|
session->next_crypto->e,
|
|
session->next_crypto->y,
|
|
session->next_crypto->p,
|
|
ctx);
|
|
}
|
|
|
|
bignum_ctx_free(ctx);
|
|
ssh_dh_debug(session);
|
|
if (rc != 1) {
|
|
return SSH_ERROR;
|
|
}
|
|
return SSH_OK;
|
|
}
|
|
|
|
static SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply);
|
|
|
|
static ssh_packet_callback dh_client_callbacks[]= {
|
|
ssh_packet_client_dh_reply
|
|
};
|
|
|
|
static struct ssh_packet_callbacks_struct ssh_dh_client_callbacks = {
|
|
.start = SSH2_MSG_KEXDH_REPLY,
|
|
.n_callbacks = 1,
|
|
.callbacks = dh_client_callbacks,
|
|
.user = NULL
|
|
};
|
|
|
|
/** @internal
|
|
* @brief Starts diffie-hellman-group1 key exchange
|
|
*/
|
|
int ssh_client_dh_init(ssh_session session){
|
|
bignum_CTX ctx = bignum_ctx_new();
|
|
int rc;
|
|
|
|
if (bignum_ctx_invalid(ctx)) {
|
|
goto error;
|
|
}
|
|
rc = ssh_dh_init_common(session);
|
|
if (rc == SSH_ERROR) {
|
|
goto error;
|
|
}
|
|
|
|
rc = ssh_dh_generate_secret(session, session->next_crypto->x);
|
|
if (rc == SSH_ERROR){
|
|
goto error;
|
|
}
|
|
session->next_crypto->e = bignum_new();
|
|
if (session->next_crypto->e == NULL){
|
|
goto error;
|
|
}
|
|
rc = bignum_mod_exp(session->next_crypto->e, session->next_crypto->g, session->next_crypto->x,
|
|
session->next_crypto->p, ctx);
|
|
|
|
bignum_ctx_free(ctx);
|
|
if (rc != 1) {
|
|
goto error;
|
|
}
|
|
rc = ssh_buffer_pack(session->out_buffer, "bB", SSH2_MSG_KEXDH_INIT, session->next_crypto->e);
|
|
if (rc != SSH_OK) {
|
|
goto error;
|
|
}
|
|
|
|
/* register the packet callbacks */
|
|
ssh_packet_set_callbacks(session, &ssh_dh_client_callbacks);
|
|
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
|
|
|
rc = ssh_packet_send(session);
|
|
return rc;
|
|
error:
|
|
ssh_dh_cleanup(session->next_crypto);
|
|
return SSH_ERROR;
|
|
}
|
|
|
|
SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
|
|
struct ssh_crypto_struct *crypto=session->next_crypto;
|
|
ssh_string pubkey_blob = NULL;
|
|
int rc;
|
|
|
|
(void)type;
|
|
(void)user;
|
|
|
|
ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks);
|
|
|
|
rc = ssh_buffer_unpack(packet, "SBS", &pubkey_blob, &crypto->f,
|
|
&crypto->dh_server_signature);
|
|
if (rc == SSH_ERROR) {
|
|
goto error;
|
|
}
|
|
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
|
|
ssh_string_free(pubkey_blob);
|
|
if (rc != 0) {
|
|
goto error;
|
|
}
|
|
|
|
rc = ssh_dh_build_k(session);
|
|
if (rc == SSH_ERROR){
|
|
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
|
goto error;
|
|
}
|
|
|
|
/* Send the MSG_NEWKEYS */
|
|
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
rc=ssh_packet_send(session);
|
|
if (rc == SSH_ERROR) {
|
|
goto error;
|
|
}
|
|
|
|
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
|
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
|
return SSH_PACKET_USED;
|
|
error:
|
|
ssh_dh_cleanup(session->next_crypto);
|
|
session->session_state=SSH_SESSION_STATE_ERROR;
|
|
return SSH_PACKET_USED;
|
|
}
|
|
|
|
#ifdef WITH_SERVER
|
|
|
|
static SSH_PACKET_CALLBACK(ssh_packet_server_dh_init);
|
|
|
|
static ssh_packet_callback dh_server_callbacks[] = {
|
|
ssh_packet_server_dh_init,
|
|
};
|
|
|
|
static struct ssh_packet_callbacks_struct ssh_dh_server_callbacks = {
|
|
.start = SSH2_MSG_KEXDH_INIT,
|
|
.n_callbacks = 1,
|
|
.callbacks = dh_server_callbacks,
|
|
.user = NULL
|
|
};
|
|
|
|
/** @internal
|
|
* @brief sets up the diffie-hellman-groupx kex callbacks
|
|
*/
|
|
void ssh_server_dh_init(ssh_session session){
|
|
/* register the packet callbacks */
|
|
ssh_packet_set_callbacks(session, &ssh_dh_server_callbacks);
|
|
|
|
ssh_dh_init_common(session);
|
|
}
|
|
|
|
/** @internal
|
|
* @brief processes a SSH_MSG_KEXDH_INIT or SSH_MSG_KEX_DH_GEX_INIT packet and sends
|
|
* the appropriate SSH_MSG_KEXDH_REPLY or SSH_MSG_KEX_DH_GEX_REPLY
|
|
*/
|
|
int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet)
|
|
{
|
|
ssh_key privkey = NULL;
|
|
ssh_string sig_blob = NULL;
|
|
ssh_string pubkey_blob = NULL;
|
|
bignum_CTX ctx = bignum_ctx_new();
|
|
int packet_type;
|
|
int rc;
|
|
|
|
if (bignum_ctx_invalid(ctx)) {
|
|
goto error;
|
|
}
|
|
rc = ssh_buffer_unpack(packet, "B", &session->next_crypto->e);
|
|
if (rc == SSH_ERROR) {
|
|
ssh_set_error(session, SSH_FATAL, "No e number in client request");
|
|
goto error;
|
|
}
|
|
|
|
rc = ssh_dh_generate_secret(session, session->next_crypto->y);
|
|
if (rc == SSH_ERROR){
|
|
goto error;
|
|
}
|
|
|
|
session->next_crypto->f = bignum_new();
|
|
if (session->next_crypto->f == NULL){
|
|
goto error;
|
|
}
|
|
rc = bignum_mod_exp(session->next_crypto->f,
|
|
session->next_crypto->g,
|
|
session->next_crypto->y,
|
|
session->next_crypto->p, ctx);
|
|
bignum_ctx_free(ctx);
|
|
ctx = NULL;
|
|
if (rc != 1) {
|
|
goto error;
|
|
}
|
|
|
|
rc = ssh_get_key_params(session, &privkey);
|
|
if (rc != SSH_OK) {
|
|
goto error;
|
|
}
|
|
rc = ssh_dh_build_k(session);
|
|
if (rc == SSH_ERROR) {
|
|
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
|
goto error;
|
|
}
|
|
rc = ssh_make_sessionid(session);
|
|
if (rc != SSH_OK) {
|
|
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
|
|
goto error;
|
|
}
|
|
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
|
|
if (sig_blob == NULL) {
|
|
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
|
|
goto error;
|
|
}
|
|
switch (session->next_crypto->kex_type){
|
|
case SSH_KEX_DH_GROUP1_SHA1:
|
|
case SSH_KEX_DH_GROUP14_SHA1:
|
|
case SSH_KEX_DH_GROUP16_SHA512:
|
|
case SSH_KEX_DH_GROUP18_SHA512:
|
|
packet_type = SSH2_MSG_KEXDH_REPLY;
|
|
break;
|
|
#ifdef WITH_GEX
|
|
case SSH_KEX_DH_GEX_SHA1:
|
|
case SSH_KEX_DH_GEX_SHA256:
|
|
packet_type = SSH2_MSG_KEX_DH_GEX_REPLY;
|
|
break;
|
|
#endif /* WITH_GEX */
|
|
default:
|
|
ssh_set_error(session, SSH_FATAL, "Invalid kex type");
|
|
goto error;
|
|
}
|
|
|
|
rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
|
|
if (rc != SSH_OK){
|
|
ssh_set_error_oom(session);
|
|
goto error;
|
|
}
|
|
rc = ssh_buffer_pack(session->out_buffer,
|
|
"bSBS",
|
|
packet_type,
|
|
pubkey_blob,
|
|
session->next_crypto->f,
|
|
sig_blob);
|
|
SSH_STRING_FREE(sig_blob);
|
|
SSH_STRING_FREE(pubkey_blob);
|
|
if(rc != SSH_OK) {
|
|
ssh_set_error_oom(session);
|
|
ssh_buffer_reinit(session->out_buffer);
|
|
goto error;
|
|
}
|
|
rc = ssh_packet_send(session);
|
|
if (rc == SSH_ERROR) {
|
|
goto error;
|
|
}
|
|
SSH_LOG(SSH_LOG_DEBUG, "Sent KEX_DH_[GEX]_REPLY");
|
|
|
|
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
|
ssh_buffer_reinit(session->out_buffer);
|
|
goto error;
|
|
}
|
|
session->dh_handshake_state=DH_STATE_NEWKEYS_SENT;
|
|
if (ssh_packet_send(session) == SSH_ERROR) {
|
|
goto error;
|
|
}
|
|
SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent");
|
|
|
|
return SSH_OK;
|
|
error:
|
|
if (!bignum_ctx_invalid(ctx)) {
|
|
bignum_ctx_free(ctx);
|
|
}
|
|
SSH_STRING_FREE(sig_blob);
|
|
SSH_STRING_FREE(pubkey_blob);
|
|
|
|
session->session_state = SSH_SESSION_STATE_ERROR;
|
|
ssh_dh_cleanup(session->next_crypto);
|
|
return SSH_ERROR;
|
|
}
|
|
|
|
/** @internal
|
|
* @brief parse an incoming SSH_MSG_KEXDH_INIT packet and complete
|
|
* Diffie-Hellman key exchange
|
|
**/
|
|
static SSH_PACKET_CALLBACK(ssh_packet_server_dh_init){
|
|
(void)type;
|
|
(void)user;
|
|
SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_KEXDH_INIT");
|
|
ssh_packet_remove_callbacks(session, &ssh_dh_server_callbacks);
|
|
ssh_server_dh_process_init(session, packet);
|
|
return SSH_PACKET_USED;
|
|
}
|
|
|
|
#endif /* WITH_SERVER */
|
|
|
|
/**
|
|
* @addtogroup libssh_session
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
|
|
ssh_key ssh_dh_get_current_server_publickey(ssh_session session)
|
|
{
|
|
if (session->current_crypto == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
return session->current_crypto->server_pubkey;
|
|
}
|
|
|
|
/* Caller need to free the blob */
|
|
int ssh_dh_get_current_server_publickey_blob(ssh_session session,
|
|
ssh_string *pubkey_blob)
|
|
{
|
|
const ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
|
|
|
|
return ssh_pki_export_pubkey_blob(pubkey, pubkey_blob);
|
|
}
|
|
|
|
ssh_key ssh_dh_get_next_server_publickey(ssh_session session)
|
|
{
|
|
return session->next_crypto->server_pubkey;
|
|
}
|
|
|
|
/* Caller need to free the blob */
|
|
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
|
|
ssh_string *pubkey_blob)
|
|
{
|
|
const ssh_key pubkey = ssh_dh_get_next_server_publickey(session);
|
|
|
|
return ssh_pki_export_pubkey_blob(pubkey, pubkey_blob);
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* @brief Convert a buffer into an unpadded base64 string.
|
|
* The caller has to free the memory.
|
|
*
|
|
* @param hash What should be converted to a base64 string.
|
|
*
|
|
* @param len Length of the buffer to convert.
|
|
*
|
|
* @return The base64 string or NULL on error.
|
|
*
|
|
* @see ssh_string_free_char()
|
|
*/
|
|
static char *ssh_get_b64_unpadded(const unsigned char *hash, size_t len)
|
|
{
|
|
char *b64_padded = NULL;
|
|
char *b64_unpadded = NULL;
|
|
size_t k;
|
|
|
|
b64_padded = (char *)bin_to_base64(hash, (int)len);
|
|
if (b64_padded == NULL) {
|
|
return NULL;
|
|
}
|
|
for (k = strlen(b64_padded); k != 0 && b64_padded[k-1] == '='; k--);
|
|
|
|
b64_unpadded = strndup(b64_padded, k);
|
|
SAFE_FREE(b64_padded);
|
|
|
|
return b64_unpadded;
|
|
}
|
|
|
|
/**
|
|
* @brief Get a hash as a human-readable hex- or base64-string.
|
|
*
|
|
* This gets an allocated fingerprint hash. It is a hex strings if the given
|
|
* hash is a md5 sum. If it is a SHA sum, it will return an unpadded base64
|
|
* strings. Either way, the output is prepended by the hash-type.
|
|
*
|
|
* @param type Which sort of hash is given.
|
|
*
|
|
* @param hash What should be converted to a base64 string.
|
|
*
|
|
* @param len Length of the buffer to convert.
|
|
*
|
|
* @return Returns the allocated fingerprint hash or NULL on error.
|
|
*
|
|
* @see ssh_string_free_char()
|
|
*/
|
|
char *ssh_get_fingerprint_hash(enum ssh_publickey_hash_type type,
|
|
unsigned char *hash,
|
|
size_t len)
|
|
{
|
|
const char *prefix = "UNKNOWN";
|
|
char *fingerprint = NULL;
|
|
char *str = NULL;
|
|
size_t str_len;
|
|
int rc;
|
|
|
|
switch (type) {
|
|
case SSH_PUBLICKEY_HASH_SHA1:
|
|
case SSH_PUBLICKEY_HASH_SHA256:
|
|
fingerprint = ssh_get_b64_unpadded(hash, len);
|
|
break;
|
|
case SSH_PUBLICKEY_HASH_MD5:
|
|
fingerprint = ssh_get_hexa(hash, len);
|
|
break;
|
|
}
|
|
if (fingerprint == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
switch (type) {
|
|
case SSH_PUBLICKEY_HASH_MD5:
|
|
prefix = "MD5";
|
|
break;
|
|
case SSH_PUBLICKEY_HASH_SHA1:
|
|
prefix = "SHA1";
|
|
break;
|
|
case SSH_PUBLICKEY_HASH_SHA256:
|
|
prefix = "SHA256";
|
|
break;
|
|
}
|
|
|
|
str_len = strlen(prefix);
|
|
if (str_len + 1 + strlen(fingerprint) + 1 < str_len) {
|
|
SAFE_FREE(fingerprint);
|
|
return NULL;
|
|
}
|
|
str_len += 1 + strlen(fingerprint) + 1;
|
|
|
|
str = malloc(str_len);
|
|
if (str == NULL) {
|
|
SAFE_FREE(fingerprint);
|
|
return NULL;
|
|
}
|
|
rc = snprintf(str, str_len, "%s:%s", prefix, fingerprint);
|
|
SAFE_FREE(fingerprint);
|
|
if (rc < 0 || rc < (int)(str_len - 1)) {
|
|
SAFE_FREE(str);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
/**
|
|
* @brief Print a hash as a human-readable hex- or base64-string.
|
|
*
|
|
* This function prints hex strings if the given hash is a md5 sum.
|
|
* But prints unpadded base64 strings for sha sums.
|
|
* Either way, the output is prepended by the hash-type.
|
|
*
|
|
* @param type Which sort of hash is given.
|
|
*
|
|
* @param hash What should be converted to a base64 string.
|
|
*
|
|
* @param len Length of the buffer to convert.
|
|
*
|
|
* @see ssh_get_publickey_hash()
|
|
* @see ssh_get_fingerprint_hash()
|
|
*/
|
|
void ssh_print_hash(enum ssh_publickey_hash_type type,
|
|
unsigned char *hash,
|
|
size_t len)
|
|
{
|
|
char *fingerprint = NULL;
|
|
|
|
fingerprint = ssh_get_fingerprint_hash(type,
|
|
hash,
|
|
len);
|
|
if (fingerprint == NULL) {
|
|
return;
|
|
}
|
|
|
|
fprintf(stderr, "%s\n", fingerprint);
|
|
|
|
SAFE_FREE(fingerprint);
|
|
}
|
|
|
|
/** @} */
|