1 /* 2 * Dropbear - a SSH2 server 3 * 4 * Copyright (c) 2002,2003 Matt Johnston 5 * All rights reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. */ 24 25 /* Perform RSA operations on data, including reading keys, signing and 26 * verification. 27 * 28 * The format is specified in rfc2437, Applied Cryptography or The Handbook of 29 * Applied Cryptography detail the general algorithm. */ 30 31 #include "includes.h" 32 #include "dbutil.h" 33 #include "bignum.h" 34 #include "rsa.h" 35 #include "buffer.h" 36 #include "ssh.h" 37 #include "random.h" 38 39 #ifdef DROPBEAR_RSA 40 41 static void rsa_pad_em(rsa_key * key, 42 const unsigned char * data, unsigned int len, 43 mp_int * rsa_em); 44 45 /* Load a public rsa key from a buffer, initialising the values. 46 * The key will have the same format as buf_put_rsa_key. 47 * These should be freed with rsa_key_free. 48 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ 49 int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) { 50 51 int ret = DROPBEAR_FAILURE; 52 TRACE(("enter buf_get_rsa_pub_key")) 53 dropbear_assert(key != NULL); 54 key->e = m_malloc(sizeof(mp_int)); 55 key->n = m_malloc(sizeof(mp_int)); 56 m_mp_init_multi(key->e, key->n, NULL); 57 key->d = NULL; 58 key->p = NULL; 59 key->q = NULL; 60 61 buf_incrpos(buf, 4+SSH_SIGNKEY_RSA_LEN); /* int + "ssh-rsa" */ 62 63 if (buf_getmpint(buf, key->e) == DROPBEAR_FAILURE 64 || buf_getmpint(buf, key->n) == DROPBEAR_FAILURE) { 65 TRACE(("leave buf_get_rsa_pub_key: failure")) 66 goto out; 67 } 68 69 if (mp_count_bits(key->n) < MIN_RSA_KEYLEN) { 70 dropbear_log(LOG_WARNING, "rsa key too short"); 71 goto out; 72 } 73 74 TRACE(("leave buf_get_rsa_pub_key: success")) 75 ret = DROPBEAR_SUCCESS; 76 out: 77 if (ret == DROPBEAR_FAILURE) { 78 m_free(key->e); 79 m_free(key->n); 80 } 81 return ret; 82 } 83 84 /* Same as buf_get_rsa_pub_key, but reads private bits at the end. 85 * Loads a private rsa key from a buffer 86 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ 87 int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) { 88 int ret = DROPBEAR_FAILURE; 89 90 TRACE(("enter buf_get_rsa_priv_key")) 91 dropbear_assert(key != NULL); 92 93 if (buf_get_rsa_pub_key(buf, key) == DROPBEAR_FAILURE) { 94 TRACE(("leave buf_get_rsa_priv_key: pub: ret == DROPBEAR_FAILURE")) 95 return DROPBEAR_FAILURE; 96 } 97 98 key->d = NULL; 99 key->p = NULL; 100 key->q = NULL; 101 102 key->d = m_malloc(sizeof(mp_int)); 103 m_mp_init(key->d); 104 if (buf_getmpint(buf, key->d) == DROPBEAR_FAILURE) { 105 TRACE(("leave buf_get_rsa_priv_key: d: ret == DROPBEAR_FAILURE")) 106 goto out; 107 } 108 109 if (buf->pos == buf->len) { 110 /* old Dropbear private keys didn't keep p and q, so we will ignore them*/ 111 } else { 112 key->p = m_malloc(sizeof(mp_int)); 113 key->q = m_malloc(sizeof(mp_int)); 114 m_mp_init_multi(key->p, key->q, NULL); 115 116 if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE) { 117 TRACE(("leave buf_get_rsa_priv_key: p: ret == DROPBEAR_FAILURE")) 118 goto out; 119 } 120 121 if (buf_getmpint(buf, key->q) == DROPBEAR_FAILURE) { 122 TRACE(("leave buf_get_rsa_priv_key: q: ret == DROPBEAR_FAILURE")) 123 goto out; 124 } 125 } 126 127 ret = DROPBEAR_SUCCESS; 128 out: 129 if (ret == DROPBEAR_FAILURE) { 130 m_free(key->d); 131 m_free(key->p); 132 m_free(key->q); 133 } 134 TRACE(("leave buf_get_rsa_priv_key")) 135 return ret; 136 } 137 138 139 /* Clear and free the memory used by a public or private key */ 140 void rsa_key_free(rsa_key *key) { 141 142 TRACE(("enter rsa_key_free")) 143 144 if (key == NULL) { 145 TRACE(("leave rsa_key_free: key == NULL")) 146 return; 147 } 148 if (key->d) { 149 mp_clear(key->d); 150 m_free(key->d); 151 } 152 if (key->e) { 153 mp_clear(key->e); 154 m_free(key->e); 155 } 156 if (key->n) { 157 mp_clear(key->n); 158 m_free(key->n); 159 } 160 if (key->p) { 161 mp_clear(key->p); 162 m_free(key->p); 163 } 164 if (key->q) { 165 mp_clear(key->q); 166 m_free(key->q); 167 } 168 m_free(key); 169 TRACE(("leave rsa_key_free")) 170 } 171 172 /* Put the public rsa key into the buffer in the required format: 173 * 174 * string "ssh-rsa" 175 * mp_int e 176 * mp_int n 177 */ 178 void buf_put_rsa_pub_key(buffer* buf, rsa_key *key) { 179 180 TRACE(("enter buf_put_rsa_pub_key")) 181 dropbear_assert(key != NULL); 182 183 buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN); 184 buf_putmpint(buf, key->e); 185 buf_putmpint(buf, key->n); 186 187 TRACE(("leave buf_put_rsa_pub_key")) 188 189 } 190 191 /* Same as buf_put_rsa_pub_key, but with the private "x" key appended */ 192 void buf_put_rsa_priv_key(buffer* buf, rsa_key *key) { 193 194 TRACE(("enter buf_put_rsa_priv_key")) 195 196 dropbear_assert(key != NULL); 197 buf_put_rsa_pub_key(buf, key); 198 buf_putmpint(buf, key->d); 199 200 /* new versions have p and q, old versions don't */ 201 if (key->p) { 202 buf_putmpint(buf, key->p); 203 } 204 if (key->q) { 205 buf_putmpint(buf, key->q); 206 } 207 208 209 TRACE(("leave buf_put_rsa_priv_key")) 210 211 } 212 213 #ifdef DROPBEAR_SIGNKEY_VERIFY 214 /* Verify a signature in buf, made on data by the key given. 215 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ 216 int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data, 217 unsigned int len) { 218 219 unsigned int slen; 220 DEF_MP_INT(rsa_s); 221 DEF_MP_INT(rsa_mdash); 222 DEF_MP_INT(rsa_em); 223 int ret = DROPBEAR_FAILURE; 224 225 TRACE(("enter buf_rsa_verify")) 226 227 dropbear_assert(key != NULL); 228 229 m_mp_init_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL); 230 231 slen = buf_getint(buf); 232 if (slen != (unsigned int)mp_unsigned_bin_size(key->n)) { 233 TRACE(("bad size")) 234 goto out; 235 } 236 237 if (mp_read_unsigned_bin(&rsa_s, buf_getptr(buf, buf->len - buf->pos), 238 buf->len - buf->pos) != MP_OKAY) { 239 TRACE(("failed reading rsa_s")) 240 goto out; 241 } 242 243 /* check that s <= n-1 */ 244 if (mp_cmp(&rsa_s, key->n) != MP_LT) { 245 TRACE(("s > n-1")) 246 goto out; 247 } 248 249 /* create the magic PKCS padded value */ 250 rsa_pad_em(key, data, len, &rsa_em); 251 252 if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) { 253 TRACE(("failed exptmod rsa_s")) 254 goto out; 255 } 256 257 if (mp_cmp(&rsa_em, &rsa_mdash) == MP_EQ) { 258 /* signature is valid */ 259 TRACE(("success!")) 260 ret = DROPBEAR_SUCCESS; 261 } 262 263 out: 264 mp_clear_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL); 265 TRACE(("leave buf_rsa_verify: ret %d", ret)) 266 return ret; 267 } 268 269 #endif /* DROPBEAR_SIGNKEY_VERIFY */ 270 271 /* Sign the data presented with key, writing the signature contents 272 * to the buffer */ 273 void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data, 274 unsigned int len) { 275 276 unsigned int nsize, ssize; 277 unsigned int i; 278 DEF_MP_INT(rsa_s); 279 DEF_MP_INT(rsa_tmp1); 280 DEF_MP_INT(rsa_tmp2); 281 DEF_MP_INT(rsa_tmp3); 282 283 TRACE(("enter buf_put_rsa_sign")) 284 dropbear_assert(key != NULL); 285 286 m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL); 287 288 rsa_pad_em(key, data, len, &rsa_tmp1); 289 290 /* the actual signing of the padded data */ 291 292 #ifdef RSA_BLINDING 293 294 /* With blinding, s = (r^(-1))((em)*r^e)^d mod n */ 295 296 /* generate the r blinding value */ 297 /* rsa_tmp2 is r */ 298 gen_random_mpint(key->n, &rsa_tmp2); 299 300 /* rsa_tmp1 is em */ 301 /* em' = em * r^e mod n */ 302 303 /* rsa_s used as a temp var*/ 304 if (mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s) != MP_OKAY) { 305 dropbear_exit("rsa error"); 306 } 307 if (mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3) != MP_OKAY) { 308 dropbear_exit("rsa error"); 309 } 310 if (mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2) != MP_OKAY) { 311 dropbear_exit("rsa error"); 312 } 313 314 /* rsa_tmp2 is em' */ 315 /* s' = (em')^d mod n */ 316 if (mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1) != MP_OKAY) { 317 dropbear_exit("rsa error"); 318 } 319 320 /* rsa_tmp1 is s' */ 321 /* rsa_tmp3 is r^(-1) mod n */ 322 /* s = (s')r^(-1) mod n */ 323 if (mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s) != MP_OKAY) { 324 dropbear_exit("rsa error"); 325 } 326 327 #else 328 329 /* s = em^d mod n */ 330 /* rsa_tmp1 is em */ 331 if (mp_exptmod(&rsa_tmp1, key->d, key->n, &rsa_s) != MP_OKAY) { 332 dropbear_exit("rsa error"); 333 } 334 335 #endif /* RSA_BLINDING */ 336 337 mp_clear_multi(&rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL); 338 339 /* create the signature to return */ 340 buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN); 341 342 nsize = mp_unsigned_bin_size(key->n); 343 344 /* string rsa_signature_blob length */ 345 buf_putint(buf, nsize); 346 /* pad out s to same length as n */ 347 ssize = mp_unsigned_bin_size(&rsa_s); 348 dropbear_assert(ssize <= nsize); 349 for (i = 0; i < nsize-ssize; i++) { 350 buf_putbyte(buf, 0x00); 351 } 352 353 if (mp_to_unsigned_bin(&rsa_s, buf_getwriteptr(buf, ssize)) != MP_OKAY) { 354 dropbear_exit("rsa error"); 355 } 356 buf_incrwritepos(buf, ssize); 357 mp_clear(&rsa_s); 358 359 #if defined(DEBUG_RSA) && defined(DEBUG_TRACE) 360 printhex("RSA sig", buf->data, buf->len); 361 #endif 362 363 364 TRACE(("leave buf_put_rsa_sign")) 365 } 366 367 /* Creates the message value as expected by PKCS, see rfc2437 etc */ 368 /* format to be padded to is: 369 * EM = 01 | FF* | 00 | prefix | hash 370 * 371 * where FF is repeated enough times to make EM one byte 372 * shorter than the size of key->n 373 * 374 * prefix is the ASN1 designator prefix, 375 * hex 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 376 * 377 * rsa_em must be a pointer to an initialised mp_int. 378 */ 379 static void rsa_pad_em(rsa_key * key, 380 const unsigned char * data, unsigned int len, 381 mp_int * rsa_em) { 382 383 /* ASN1 designator (including the 0x00 preceding) */ 384 const unsigned char rsa_asn1_magic[] = 385 {0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 386 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}; 387 const unsigned int RSA_ASN1_MAGIC_LEN = 16; 388 389 buffer * rsa_EM = NULL; 390 hash_state hs; 391 unsigned int nsize; 392 393 dropbear_assert(key != NULL); 394 dropbear_assert(data != NULL); 395 nsize = mp_unsigned_bin_size(key->n); 396 397 rsa_EM = buf_new(nsize-1); 398 /* type byte */ 399 buf_putbyte(rsa_EM, 0x01); 400 /* Padding with 0xFF bytes */ 401 while(rsa_EM->pos != rsa_EM->size - RSA_ASN1_MAGIC_LEN - SHA1_HASH_SIZE) { 402 buf_putbyte(rsa_EM, 0xff); 403 } 404 /* Magic ASN1 stuff */ 405 memcpy(buf_getwriteptr(rsa_EM, RSA_ASN1_MAGIC_LEN), 406 rsa_asn1_magic, RSA_ASN1_MAGIC_LEN); 407 buf_incrwritepos(rsa_EM, RSA_ASN1_MAGIC_LEN); 408 409 /* The hash of the data */ 410 sha1_init(&hs); 411 sha1_process(&hs, data, len); 412 sha1_done(&hs, buf_getwriteptr(rsa_EM, SHA1_HASH_SIZE)); 413 buf_incrwritepos(rsa_EM, SHA1_HASH_SIZE); 414 415 dropbear_assert(rsa_EM->pos == rsa_EM->size); 416 417 /* Create the mp_int from the encoded bytes */ 418 buf_setpos(rsa_EM, 0); 419 bytes_to_mp(rsa_em, buf_getptr(rsa_EM, rsa_EM->size), 420 rsa_EM->size); 421 buf_free(rsa_EM); 422 } 423 424 #endif /* DROPBEAR_RSA */ 425