/* * 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 * Copyright (c) 2012 by Dmitriy Kuznetsov * * 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); } /** @} */