[BACK]Return to sshkey.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/sshkey.c between version 1.45 and 1.46

version 1.45, 2017/03/10 04:07:20 version 1.46, 2017/04/30 23:10:43
Line 85 
Line 85 
         { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",          { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
             KEY_ED25519_CERT, 0, 1, 0 },              KEY_ED25519_CERT, 0, 1, 0 },
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
 # ifdef WITH_SSH1  
         { NULL, "RSA1", KEY_RSA1, 0, 0, 0 },  
 # endif  
         { "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 },          { "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 },
         { "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 },          { "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 },
         { "rsa-sha2-512", "RSA", KEY_RSA, 0, 0, 1 },          { "rsa-sha2-512", "RSA", KEY_RSA, 0, 0, 1 },
Line 1168 
Line 1165 
         return retval;          return retval;
 }  }
   
 #ifdef WITH_SSH1  
 /*  
  * Reads a multiple-precision integer in decimal from the buffer, and advances  
  * the pointer.  The integer must already be initialized.  This function is  
  * permitted to modify the buffer.  This leaves *cpp to point just beyond the  
  * last processed character.  
  */  
 static int  
 read_decimal_bignum(char **cpp, BIGNUM *v)  
 {  
         char *cp;  
         size_t e;  
         int skip = 1;   /* skip white space */  
   
         cp = *cpp;  
         while (*cp == ' ' || *cp == '\t')  
                 cp++;  
         e = strspn(cp, "0123456789");  
         if (e == 0)  
                 return SSH_ERR_INVALID_FORMAT;  
         if (e > SSHBUF_MAX_BIGNUM * 3)  
                 return SSH_ERR_BIGNUM_TOO_LARGE;  
         if (cp[e] == '\0')  
                 skip = 0;  
         else if (strchr(" \t\r\n", cp[e]) == NULL)  
                 return SSH_ERR_INVALID_FORMAT;  
         cp[e] = '\0';  
         if (BN_dec2bn(&v, cp) <= 0)  
                 return SSH_ERR_INVALID_FORMAT;  
         *cpp = cp + e + skip;  
         return 0;  
 }  
 #endif /* WITH_SSH1 */  
   
 /* returns 0 ok, and < 0 error */  /* returns 0 ok, and < 0 error */
 int  int
 sshkey_read(struct sshkey *ret, char **cpp)  sshkey_read(struct sshkey *ret, char **cpp)
Line 1211 
Line 1175 
         char *ep, *cp, *space;          char *ep, *cp, *space;
         int r, type, curve_nid = -1;          int r, type, curve_nid = -1;
         struct sshbuf *blob;          struct sshbuf *blob;
 #ifdef WITH_SSH1  
         u_long bits;  
 #endif /* WITH_SSH1 */  
   
         if (ret == NULL)          if (ret == NULL)
                 return SSH_ERR_INVALID_ARGUMENT;                  return SSH_ERR_INVALID_ARGUMENT;
Line 1222 
Line 1183 
   
         switch (ret->type) {          switch (ret->type) {
         case KEY_RSA1:          case KEY_RSA1:
 #ifdef WITH_SSH1  
                 /* Get number of bits. */  
                 bits = strtoul(cp, &ep, 10);  
                 if (*cp == '\0' || strchr(" \t\r\n", *ep) == NULL ||  
                     bits == 0 || bits > SSHBUF_MAX_BIGNUM * 8)  
                         return SSH_ERR_INVALID_FORMAT;  /* Bad bit count... */  
                 /* Get public exponent, public modulus. */  
                 if ((r = read_decimal_bignum(&ep, ret->rsa->e)) < 0)  
                         return r;  
                 if ((r = read_decimal_bignum(&ep, ret->rsa->n)) < 0)  
                         return r;  
                 /* validate the claimed number of bits */  
                 if (BN_num_bits(ret->rsa->n) != (int)bits)  
                         return SSH_ERR_KEY_BITS_MISMATCH;  
                 *cpp = ep;  
                 retval = 0;  
 #endif /* WITH_SSH1 */  
                 break;                  break;
         case KEY_UNSPEC:          case KEY_UNSPEC:
         case KEY_RSA:          case KEY_RSA:
Line 1394 
Line 1338 
 sshkey_format_rsa1(const struct sshkey *key, struct sshbuf *b)  sshkey_format_rsa1(const struct sshkey *key, struct sshbuf *b)
 {  {
         int r = SSH_ERR_INTERNAL_ERROR;          int r = SSH_ERR_INTERNAL_ERROR;
 #ifdef WITH_SSH1  
         u_int bits = 0;  
         char *dec_e = NULL, *dec_n = NULL;  
   
         if (key->rsa == NULL || key->rsa->e == NULL ||  
             key->rsa->n == NULL) {  
                 r = SSH_ERR_INVALID_ARGUMENT;  
                 goto out;  
         }  
         if ((dec_e = BN_bn2dec(key->rsa->e)) == NULL ||  
             (dec_n = BN_bn2dec(key->rsa->n)) == NULL) {  
                 r = SSH_ERR_ALLOC_FAIL;  
                 goto out;  
         }  
         /* size of modulus 'n' */  
         if ((bits = BN_num_bits(key->rsa->n)) <= 0) {  
                 r = SSH_ERR_INVALID_ARGUMENT;  
                 goto out;  
         }  
         if ((r = sshbuf_putf(b, "%u %s %s", bits, dec_e, dec_n)) != 0)  
                 goto out;  
   
         /* Success */  
         r = 0;  
  out:  
         if (dec_e != NULL)  
                 OPENSSL_free(dec_e);  
         if (dec_n != NULL)  
                 OPENSSL_free(dec_n);  
 #endif /* WITH_SSH1 */  
   
         return r;          return r;
 }  }
   
Line 3354 
Line 3268 
         return r;          return r;
 }  }
   
 #if WITH_SSH1  
 /*  
  * Serialises the authentication (private) key to a blob, encrypting it with  
  * passphrase.  The identification of the blob (lowest 64 bits of n) will  
  * precede the key to provide identification of the key without needing a  
  * passphrase.  
  */  
 static int  
 sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob,  
     const char *passphrase, const char *comment)  
 {  
         struct sshbuf *buffer = NULL, *encrypted = NULL;  
         u_char buf[8];  
         int r, cipher_num;  
         struct sshcipher_ctx *ciphercontext = NULL;  
         const struct sshcipher *cipher;  
         u_char *cp;  
   
         /*  
          * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting  
          * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.  
          */  
         cipher_num = (strcmp(passphrase, "") == 0) ?  
             SSH_CIPHER_NONE : SSH_CIPHER_3DES;  
         if ((cipher = cipher_by_number(cipher_num)) == NULL)  
                 return SSH_ERR_INTERNAL_ERROR;  
   
         /* This buffer is used to build the secret part of the private key. */  
         if ((buffer = sshbuf_new()) == NULL)  
                 return SSH_ERR_ALLOC_FAIL;  
   
         /* Put checkbytes for checking passphrase validity. */  
         if ((r = sshbuf_reserve(buffer, 4, &cp)) != 0)  
                 goto out;  
         arc4random_buf(cp, 2);  
         memcpy(cp + 2, cp, 2);  
   
         /*  
          * Store the private key (n and e will not be stored because they  
          * will be stored in plain text, and storing them also in encrypted  
          * format would just give known plaintext).  
          * Note: q and p are stored in reverse order to SSL.  
          */  
         if ((r = sshbuf_put_bignum1(buffer, key->rsa->d)) != 0 ||  
             (r = sshbuf_put_bignum1(buffer, key->rsa->iqmp)) != 0 ||  
             (r = sshbuf_put_bignum1(buffer, key->rsa->q)) != 0 ||  
             (r = sshbuf_put_bignum1(buffer, key->rsa->p)) != 0)  
                 goto out;  
   
         /* Pad the part to be encrypted to a size that is a multiple of 8. */  
         explicit_bzero(buf, 8);  
         if ((r = sshbuf_put(buffer, buf, 8 - (sshbuf_len(buffer) % 8))) != 0)  
                 goto out;  
   
         /* This buffer will be used to contain the data in the file. */  
         if ((encrypted = sshbuf_new()) == NULL) {  
                 r = SSH_ERR_ALLOC_FAIL;  
                 goto out;  
         }  
   
         /* First store keyfile id string. */  
         if ((r = sshbuf_put(encrypted, LEGACY_BEGIN,  
             sizeof(LEGACY_BEGIN))) != 0)  
                 goto out;  
   
         /* Store cipher type and "reserved" field. */  
         if ((r = sshbuf_put_u8(encrypted, cipher_num)) != 0 ||  
             (r = sshbuf_put_u32(encrypted, 0)) != 0)  
                 goto out;  
   
         /* Store public key.  This will be in plain text. */  
         if ((r = sshbuf_put_u32(encrypted, BN_num_bits(key->rsa->n))) != 0 ||  
             (r = sshbuf_put_bignum1(encrypted, key->rsa->n)) != 0 ||  
             (r = sshbuf_put_bignum1(encrypted, key->rsa->e)) != 0 ||  
             (r = sshbuf_put_cstring(encrypted, comment)) != 0)  
                 goto out;  
   
         /* Allocate space for the private part of the key in the buffer. */  
         if ((r = sshbuf_reserve(encrypted, sshbuf_len(buffer), &cp)) != 0)  
                 goto out;  
   
         if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase,  
             CIPHER_ENCRYPT)) != 0)  
                 goto out;  
         if ((r = cipher_crypt(ciphercontext, 0, cp,  
             sshbuf_ptr(buffer), sshbuf_len(buffer), 0, 0)) != 0)  
                 goto out;  
   
         r = sshbuf_putb(blob, encrypted);  
   
  out:  
         cipher_free(ciphercontext);  
         explicit_bzero(buf, sizeof(buf));  
         sshbuf_free(buffer);  
         sshbuf_free(encrypted);  
   
         return r;  
 }  
 #endif /* WITH_SSH1 */  
   
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
 /* convert SSH v2 key in OpenSSL PEM format */  /* convert SSH v2 key in OpenSSL PEM format */
 static int  static int
Line 3513 
Line 3328 
     int force_new_format, const char *new_format_cipher, int new_format_rounds)      int force_new_format, const char *new_format_cipher, int new_format_rounds)
 {  {
         switch (key->type) {          switch (key->type) {
 #ifdef WITH_SSH1  
         case KEY_RSA1:  
                 return sshkey_private_rsa1_to_blob(key, blob,  
                     passphrase, comment);  
 #endif /* WITH_SSH1 */  
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         case KEY_DSA:          case KEY_DSA:
         case KEY_ECDSA:          case KEY_ECDSA:
Line 3537 
Line 3347 
         }          }
 }  }
   
 #ifdef WITH_SSH1  
 /*  
  * Parse the public, unencrypted portion of a RSA1 key.  
  */  
 int  
 sshkey_parse_public_rsa1_fileblob(struct sshbuf *blob,  
     struct sshkey **keyp, char **commentp)  
 {  
         int r;  
         struct sshkey *pub = NULL;  
         struct sshbuf *copy = NULL;  
   
         if (keyp != NULL)  
                 *keyp = NULL;  
         if (commentp != NULL)  
                 *commentp = NULL;  
   
         /* Check that it is at least big enough to contain the ID string. */  
         if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN))  
                 return SSH_ERR_INVALID_FORMAT;  
   
         /*  
          * Make sure it begins with the id string.  Consume the id string  
          * from the buffer.  
          */  
         if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0)  
                 return SSH_ERR_INVALID_FORMAT;  
         /* Make a working copy of the keyblob and skip past the magic */  
         if ((copy = sshbuf_fromb(blob)) == NULL)  
                 return SSH_ERR_ALLOC_FAIL;  
         if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0)  
                 goto out;  
   
         /* Skip cipher type, reserved data and key bits. */  
         if ((r = sshbuf_get_u8(copy, NULL)) != 0 ||     /* cipher type */  
             (r = sshbuf_get_u32(copy, NULL)) != 0 ||    /* reserved */  
             (r = sshbuf_get_u32(copy, NULL)) != 0)      /* key bits */  
                 goto out;  
   
         /* Read the public key from the buffer. */  
         if ((pub = sshkey_new(KEY_RSA1)) == NULL ||  
             (r = sshbuf_get_bignum1(copy, pub->rsa->n)) != 0 ||  
             (r = sshbuf_get_bignum1(copy, pub->rsa->e)) != 0)  
                 goto out;  
   
         /* Finally, the comment */  
         if ((r = sshbuf_get_string(copy, (u_char**)commentp, NULL)) != 0)  
                 goto out;  
   
         /* The encrypted private part is not parsed by this function. */  
   
         r = 0;  
         if (keyp != NULL) {  
                 *keyp = pub;  
                 pub = NULL;  
         }  
  out:  
         sshbuf_free(copy);  
         sshkey_free(pub);  
         return r;  
 }  
   
 static int  
 sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase,  
     struct sshkey **keyp, char **commentp)  
 {  
         int r;  
         u_int16_t check1, check2;  
         u_int8_t cipher_type;  
         struct sshbuf *decrypted = NULL, *copy = NULL;  
         u_char *cp;  
         char *comment = NULL;  
         struct sshcipher_ctx *ciphercontext = NULL;  
         const struct sshcipher *cipher;  
         struct sshkey *prv = NULL;  
   
         if (keyp != NULL)  
                 *keyp = NULL;  
         if (commentp != NULL)  
                 *commentp = NULL;  
   
         /* Check that it is at least big enough to contain the ID string. */  
         if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN))  
                 return SSH_ERR_INVALID_FORMAT;  
   
         /*  
          * Make sure it begins with the id string.  Consume the id string  
          * from the buffer.  
          */  
         if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0)  
                 return SSH_ERR_INVALID_FORMAT;  
   
         if ((prv = sshkey_new_private(KEY_RSA1)) == NULL) {  
                 r = SSH_ERR_ALLOC_FAIL;  
                 goto out;  
         }  
         if ((copy = sshbuf_fromb(blob)) == NULL ||  
             (decrypted = sshbuf_new()) == NULL) {  
                 r = SSH_ERR_ALLOC_FAIL;  
                 goto out;  
         }  
         if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0)  
                 goto out;  
   
         /* Read cipher type. */  
         if ((r = sshbuf_get_u8(copy, &cipher_type)) != 0 ||  
             (r = sshbuf_get_u32(copy, NULL)) != 0)      /* reserved */  
                 goto out;  
   
         /* Read the public key and comment from the buffer. */  
         if ((r = sshbuf_get_u32(copy, NULL)) != 0 ||    /* key bits */  
             (r = sshbuf_get_bignum1(copy, prv->rsa->n)) != 0 ||  
             (r = sshbuf_get_bignum1(copy, prv->rsa->e)) != 0 ||  
             (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0)  
                 goto out;  
   
         /* Check that it is a supported cipher. */  
         cipher = cipher_by_number(cipher_type);  
         if (cipher == NULL) {  
                 r = SSH_ERR_KEY_UNKNOWN_CIPHER;  
                 goto out;  
         }  
         /* Initialize space for decrypted data. */  
         if ((r = sshbuf_reserve(decrypted, sshbuf_len(copy), &cp)) != 0)  
                 goto out;  
   
         /* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */  
         if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase,  
             CIPHER_DECRYPT)) != 0)  
                 goto out;  
         if ((r = cipher_crypt(ciphercontext, 0, cp,  
             sshbuf_ptr(copy), sshbuf_len(copy), 0, 0)) != 0)  
                 goto out;  
   
         if ((r = sshbuf_get_u16(decrypted, &check1)) != 0 ||  
             (r = sshbuf_get_u16(decrypted, &check2)) != 0)  
                 goto out;  
         if (check1 != check2) {  
                 r = SSH_ERR_KEY_WRONG_PASSPHRASE;  
                 goto out;  
         }  
   
         /* Read the rest of the private key. */  
         if ((r = sshbuf_get_bignum1(decrypted, prv->rsa->d)) != 0 ||  
             (r = sshbuf_get_bignum1(decrypted, prv->rsa->iqmp)) != 0 ||  
             (r = sshbuf_get_bignum1(decrypted, prv->rsa->q)) != 0 ||  
             (r = sshbuf_get_bignum1(decrypted, prv->rsa->p)) != 0)  
                 goto out;  
   
         /* calculate p-1 and q-1 */  
         if ((r = rsa_generate_additional_parameters(prv->rsa)) != 0)  
                 goto out;  
   
         /* enable blinding */  
         if (RSA_blinding_on(prv->rsa, NULL) != 1) {  
                 r = SSH_ERR_LIBCRYPTO_ERROR;  
                 goto out;  
         }  
         r = 0;  
         if (keyp != NULL) {  
                 *keyp = prv;  
                 prv = NULL;  
         }  
         if (commentp != NULL) {  
                 *commentp = comment;  
                 comment = NULL;  
         }  
  out:  
         cipher_free(ciphercontext);  
         free(comment);  
         sshkey_free(prv);  
         sshbuf_free(copy);  
         sshbuf_free(decrypted);  
         return r;  
 }  
 #endif /* WITH_SSH1 */  
   
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
 static int  static int
 sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,  sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
Line 3854 
Line 3488 
                 *commentp = NULL;                  *commentp = NULL;
   
         switch (type) {          switch (type) {
 #ifdef WITH_SSH1  
         case KEY_RSA1:  
                 return sshkey_parse_private_rsa1(blob, passphrase,  
                     keyp, commentp);  
 #endif /* WITH_SSH1 */  
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         case KEY_DSA:          case KEY_DSA:
         case KEY_ECDSA:          case KEY_ECDSA:
Line 3895 
Line 3524 
         if (commentp != NULL)          if (commentp != NULL)
                 *commentp = NULL;                  *commentp = NULL;
   
 #ifdef WITH_SSH1  
         /* it's a SSH v1 key if the public key part is readable */  
         if (sshkey_parse_public_rsa1_fileblob(buffer, NULL, NULL) == 0) {  
                 return sshkey_parse_private_fileblob_type(buffer, KEY_RSA1,  
                     passphrase, keyp, commentp);  
         }  
 #endif /* WITH_SSH1 */  
         return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,          return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
             passphrase, keyp, commentp);              passphrase, keyp, commentp);
 }  }

Legend:
Removed from v.1.45  
changed lines
  Added in v.1.46