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

Diff for /src/usr.bin/ssh/authfile.c between version 1.7 and 1.8

version 1.7, 1999/10/11 20:00:35 version 1.8, 1999/11/23 22:25:52
Line 36 
Line 36 
 save_private_key(const char *filename, const char *passphrase,  save_private_key(const char *filename, const char *passphrase,
                  RSA *key, const char *comment)                   RSA *key, const char *comment)
 {  {
   Buffer buffer, encrypted;          Buffer buffer, encrypted;
   char buf[100], *cp;          char buf[100], *cp;
   int f, i;          int f, i;
   CipherContext cipher;          CipherContext cipher;
   int cipher_type;          int cipher_type;
   u_int32_t rand;          u_int32_t rand;
   
   /* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting to          /* If the passphrase is empty, use SSH_CIPHER_NONE to ease
      another cipher; otherwise use SSH_AUTHFILE_CIPHER. */             converting to another cipher; otherwise use
   if (strcmp(passphrase, "") == 0)             SSH_AUTHFILE_CIPHER. */
     cipher_type = SSH_CIPHER_NONE;          if (strcmp(passphrase, "") == 0)
   else                  cipher_type = SSH_CIPHER_NONE;
     cipher_type = SSH_AUTHFILE_CIPHER;          else
                   cipher_type = SSH_AUTHFILE_CIPHER;
   
   /* This buffer is used to built the secret part of the private key. */          /* This buffer is used to built the secret part of the private key. */
   buffer_init(&buffer);          buffer_init(&buffer);
   
   /* Put checkbytes for checking passphrase validity. */  
   rand = arc4random();  
   buf[0] = rand & 0xff;  
   buf[1] = (rand >> 8) & 0xff;  
   buf[2] = buf[0];  
   buf[3] = buf[1];  
   buffer_append(&buffer, buf, 4);  
   
   /* Store the private key (n and e will not be stored because they will          /* Put checkbytes for checking passphrase validity. */
      be stored in plain text, and storing them also in encrypted format          rand = arc4random();
      would just give known plaintext). */          buf[0] = rand & 0xff;
   buffer_put_bignum(&buffer, key->d);          buf[1] = (rand >> 8) & 0xff;
   buffer_put_bignum(&buffer, key->iqmp);          buf[2] = buf[0];
   buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */          buf[3] = buf[1];
   buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */          buffer_append(&buffer, buf, 4);
   
   /* Pad the part to be encrypted until its size is a multiple of 8. */          /* Store the private key (n and e will not be stored because they
   while (buffer_len(&buffer) % 8 != 0)             will be stored in plain text, and storing them also in
     buffer_put_char(&buffer, 0);             encrypted format would just give known plaintext). */
           buffer_put_bignum(&buffer, key->d);
           buffer_put_bignum(&buffer, key->iqmp);
           buffer_put_bignum(&buffer, key->q);     /* reverse from SSL p */
           buffer_put_bignum(&buffer, key->p);     /* reverse from SSL q */
   
   /* This buffer will be used to contain the data in the file. */          /* Pad the part to be encrypted until its size is a multiple of 8. */
   buffer_init(&encrypted);          while (buffer_len(&buffer) % 8 != 0)
                   buffer_put_char(&buffer, 0);
   
   /* First store keyfile id string. */          /* This buffer will be used to contain the data in the file. */
   cp = AUTHFILE_ID_STRING;          buffer_init(&encrypted);
   for (i = 0; cp[i]; i++)  
     buffer_put_char(&encrypted, cp[i]);  
   buffer_put_char(&encrypted, 0);  
   
   /* Store cipher type. */          /* First store keyfile id string. */
   buffer_put_char(&encrypted, cipher_type);          cp = AUTHFILE_ID_STRING;
   buffer_put_int(&encrypted, 0);  /* For future extension */          for (i = 0; cp[i]; i++)
                   buffer_put_char(&encrypted, cp[i]);
           buffer_put_char(&encrypted, 0);
   
   /* Store public key.  This will be in plain text. */          /* Store cipher type. */
   buffer_put_int(&encrypted, BN_num_bits(key->n));          buffer_put_char(&encrypted, cipher_type);
   buffer_put_bignum(&encrypted, key->n);          buffer_put_int(&encrypted, 0);  /* For future extension */
   buffer_put_bignum(&encrypted, key->e);  
   buffer_put_string(&encrypted, comment, strlen(comment));  
   
   /* Allocate space for the private part of the key in the buffer. */          /* Store public key.  This will be in plain text. */
   buffer_append_space(&encrypted, &cp, buffer_len(&buffer));          buffer_put_int(&encrypted, BN_num_bits(key->n));
           buffer_put_bignum(&encrypted, key->n);
           buffer_put_bignum(&encrypted, key->e);
           buffer_put_string(&encrypted, comment, strlen(comment));
   
   cipher_set_key_string(&cipher, cipher_type, passphrase, 1);          /* Allocate space for the private part of the key in the buffer. */
   cipher_encrypt(&cipher, (unsigned char *)cp,          buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
                  (unsigned char *)buffer_ptr(&buffer),  
                  buffer_len(&buffer));  
   memset(&cipher, 0, sizeof(cipher));  
   
   /* Destroy temporary data. */          cipher_set_key_string(&cipher, cipher_type, passphrase, 1);
   memset(buf, 0, sizeof(buf));          cipher_encrypt(&cipher, (unsigned char *) cp,
   buffer_free(&buffer);                         (unsigned char *) buffer_ptr(&buffer),
                          buffer_len(&buffer));
           memset(&cipher, 0, sizeof(cipher));
   
   /* Write to a file. */          /* Destroy temporary data. */
   f = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);          memset(buf, 0, sizeof(buf));
   if (f < 0)          buffer_free(&buffer);
     return 0;  
   
   if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=          /* Write to a file. */
       buffer_len(&encrypted))          f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
     {          if (f < 0)
       debug("Write to key file %.200s failed: %.100s", filename,                  return 0;
             strerror(errno));  
       buffer_free(&encrypted);          if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
       close(f);              buffer_len(&encrypted)) {
       remove(filename);                  debug("Write to key file %.200s failed: %.100s", filename,
       return 0;                        strerror(errno));
     }                  buffer_free(&encrypted);
   close(f);                  close(f);
   buffer_free(&encrypted);                  remove(filename);
   return 1;                  return 0;
           }
           close(f);
           buffer_free(&encrypted);
           return 1;
 }  }
   
 /* Loads the public part of the key file.  Returns 0 if an error  /* Loads the public part of the key file.  Returns 0 if an error
Line 130 
Line 130 
    non-zero otherwise. */     non-zero otherwise. */
   
 int  int
 load_public_key(const char *filename, RSA *pub,  load_public_key(const char *filename, RSA * pub,
                 char **comment_return)                  char **comment_return)
 {  {
   int f, i;          int f, i;
   off_t len;          off_t len;
   Buffer buffer;          Buffer buffer;
   char *cp;          char *cp;
   
   /* Read data from the file into the buffer. */          /* Read data from the file into the buffer. */
   f = open(filename, O_RDONLY);          f = open(filename, O_RDONLY);
   if (f < 0)          if (f < 0)
     return 0;                  return 0;
   
   len = lseek(f, (off_t)0, SEEK_END);          len = lseek(f, (off_t) 0, SEEK_END);
   lseek(f, (off_t)0, SEEK_SET);          lseek(f, (off_t) 0, SEEK_SET);
   
   buffer_init(&buffer);  
   buffer_append_space(&buffer, &cp, len);  
   
   if (read(f, cp, (size_t)len) != (size_t)len)          buffer_init(&buffer);
     {          buffer_append_space(&buffer, &cp, len);
       debug("Read from key file %.200s failed: %.100s", filename,  
             strerror(errno));  
       buffer_free(&buffer);  
       close(f);  
       return 0;  
     }  
   close(f);  
   
   /* Check that it is at least big enought to contain the ID string. */          if (read(f, cp, (size_t) len) != (size_t) len) {
   if (len < strlen(AUTHFILE_ID_STRING) + 1)                  debug("Read from key file %.200s failed: %.100s", filename,
     {                        strerror(errno));
       debug("Bad key file %.200s.", filename);                  buffer_free(&buffer);
       buffer_free(&buffer);                  close(f);
       return 0;                  return 0;
     }          }
           close(f);
   
   /* Make sure it begins with the id string.  Consume the id string from          /* Check that it is at least big enought to contain the ID string. */
      the buffer. */          if (len < strlen(AUTHFILE_ID_STRING) + 1) {
   for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++)                  debug("Bad key file %.200s.", filename);
     if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i])                  buffer_free(&buffer);
       {                  return 0;
         debug("Bad key file %.200s.", filename);          }
         buffer_free(&buffer);          /* Make sure it begins with the id string.  Consume the id string
         return 0;             from the buffer. */
       }          for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
                   if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
                           debug("Bad key file %.200s.", filename);
                           buffer_free(&buffer);
                           return 0;
                   }
           /* Skip cipher type and reserved data. */
           (void) buffer_get_char(&buffer);        /* cipher type */
           (void) buffer_get_int(&buffer);         /* reserved */
   
   /* Skip cipher type and reserved data. */          /* Read the public key from the buffer. */
   (void)buffer_get_char(&buffer); /* cipher type */          buffer_get_int(&buffer);
   (void)buffer_get_int(&buffer); /* reserved */          pub->n = BN_new();
           buffer_get_bignum(&buffer, pub->n);
           pub->e = BN_new();
           buffer_get_bignum(&buffer, pub->e);
           if (comment_return)
                   *comment_return = buffer_get_string(&buffer, NULL);
           /* The encrypted private part is not parsed by this function. */
   
   /* Read the public key from the buffer. */          buffer_free(&buffer);
   buffer_get_int(&buffer);  
   pub->n = BN_new();  
   buffer_get_bignum(&buffer, pub->n);  
   pub->e = BN_new();  
   buffer_get_bignum(&buffer, pub->e);  
   if (comment_return)  
     *comment_return = buffer_get_string(&buffer, NULL);  
   /* The encrypted private part is not parsed by this function. */  
   
   buffer_free(&buffer);          return 1;
   
   return 1;  
 }  }
   
 /* Loads the private key from the file.  Returns 0 if an error is encountered  /* Loads the private key from the file.  Returns 0 if an error is encountered
Line 202 
Line 197 
   
 int  int
 load_private_key(const char *filename, const char *passphrase,  load_private_key(const char *filename, const char *passphrase,
                  RSA *prv, char **comment_return)                   RSA * prv, char **comment_return)
 {  {
   int f, i, check1, check2, cipher_type;          int f, i, check1, check2, cipher_type;
   off_t len;          off_t len;
   Buffer buffer, decrypted;          Buffer buffer, decrypted;
   char *cp;          char *cp;
   CipherContext cipher;          CipherContext cipher;
   BN_CTX *ctx;          BN_CTX *ctx;
   BIGNUM *aux;          BIGNUM *aux;
   struct stat st;          struct stat st;
   
   /* Read the file into the buffer. */          /* Read the file into the buffer. */
   f = open(filename, O_RDONLY);          f = open(filename, O_RDONLY);
   if (f < 0)          if (f < 0)
     return 0;                  return 0;
   
   /* We assume we are called under uid of the owner of the file */          /* We assume we are called under uid of the owner of the file */
   if (fstat(f, &st) < 0 ||          if (fstat(f, &st) < 0 ||
       (st.st_uid != 0 && st.st_uid != getuid()) ||              (st.st_uid != 0 && st.st_uid != getuid()) ||
       (st.st_mode & 077) != 0) {              (st.st_mode & 077) != 0) {
     error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");                  error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
     error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");                  error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
     error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");                  error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
     error("Bad ownership or mode(0%3.3o) for '%s'.",                  error("Bad ownership or mode(0%3.3o) for '%s'.",
            st.st_mode & 0777, filename);                        st.st_mode & 0777, filename);
     error("It is recommended that your private key files are NOT accessible by others.");                  error("It is recommended that your private key files are NOT accessible by others.");
     return 0;                  return 0;
   }          }
           len = lseek(f, (off_t) 0, SEEK_END);
           lseek(f, (off_t) 0, SEEK_SET);
   
   len = lseek(f, (off_t)0, SEEK_END);          buffer_init(&buffer);
   lseek(f, (off_t)0, SEEK_SET);          buffer_append_space(&buffer, &cp, len);
   
   buffer_init(&buffer);  
   buffer_append_space(&buffer, &cp, len);  
   
   if (read(f, cp, (size_t)len) != (size_t)len)          if (read(f, cp, (size_t) len) != (size_t) len) {
     {                  debug("Read from key file %.200s failed: %.100s", filename,
       debug("Read from key file %.200s failed: %.100s", filename,                        strerror(errno));
             strerror(errno));                  buffer_free(&buffer);
       buffer_free(&buffer);                  close(f);
       close(f);                  return 0;
       return 0;          }
     }          close(f);
   close(f);  
   
   /* Check that it is at least big enought to contain the ID string. */          /* Check that it is at least big enought to contain the ID string. */
   if (len < strlen(AUTHFILE_ID_STRING) + 1)          if (len < strlen(AUTHFILE_ID_STRING) + 1) {
     {                  debug("Bad key file %.200s.", filename);
       debug("Bad key file %.200s.", filename);                  buffer_free(&buffer);
       buffer_free(&buffer);                  return 0;
       return 0;          }
     }          /* Make sure it begins with the id string.  Consume the id string
              from the buffer. */
           for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
                   if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
                           debug("Bad key file %.200s.", filename);
                           buffer_free(&buffer);
                           return 0;
                   }
           /* Read cipher type. */
           cipher_type = buffer_get_char(&buffer);
           (void) buffer_get_int(&buffer); /* Reserved data. */
   
   /* Make sure it begins with the id string.  Consume the id string from          /* Read the public key from the buffer. */
      the buffer. */          buffer_get_int(&buffer);
   for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++)          prv->n = BN_new();
     if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i])          buffer_get_bignum(&buffer, prv->n);
       {          prv->e = BN_new();
         debug("Bad key file %.200s.", filename);          buffer_get_bignum(&buffer, prv->e);
         buffer_free(&buffer);          if (comment_return)
         return 0;                  *comment_return = buffer_get_string(&buffer, NULL);
       }          else
                   xfree(buffer_get_string(&buffer, NULL));
   
   /* Read cipher type. */          /* Check that it is a supported cipher. */
   cipher_type = buffer_get_char(&buffer);          if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
   (void)buffer_get_int(&buffer);  /* Reserved data. */               (1 << cipher_type)) == 0) {
                   debug("Unsupported cipher %.100s used in key file %.200s.",
                         cipher_name(cipher_type), filename);
                   buffer_free(&buffer);
                   goto fail;
           }
           /* Initialize space for decrypted data. */
           buffer_init(&decrypted);
           buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
   
   /* Read the public key from the buffer. */          /* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
   buffer_get_int(&buffer);          cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
   prv->n = BN_new();          cipher_decrypt(&cipher, (unsigned char *) cp,
   buffer_get_bignum(&buffer, prv->n);                         (unsigned char *) buffer_ptr(&buffer),
   prv->e = BN_new();                         buffer_len(&buffer));
   buffer_get_bignum(&buffer, prv->e);  
   if (comment_return)  
     *comment_return = buffer_get_string(&buffer, NULL);  
   else  
     xfree(buffer_get_string(&buffer, NULL));  
   
   /* Check that it is a supported cipher. */          buffer_free(&buffer);
   if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &  
         (1 << cipher_type)) == 0)  
     {  
       debug("Unsupported cipher %.100s used in key file %.200s.",  
             cipher_name(cipher_type), filename);  
       buffer_free(&buffer);  
       goto fail;  
     }  
   
   /* Initialize space for decrypted data. */          check1 = buffer_get_char(&decrypted);
   buffer_init(&decrypted);          check2 = buffer_get_char(&decrypted);
   buffer_append_space(&decrypted, &cp, buffer_len(&buffer));          if (check1 != buffer_get_char(&decrypted) ||
               check2 != buffer_get_char(&decrypted)) {
   /* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */                  if (strcmp(passphrase, "") != 0)
   cipher_set_key_string(&cipher, cipher_type, passphrase, 0);                          debug("Bad passphrase supplied for key file %.200s.", filename);
   cipher_decrypt(&cipher, (unsigned char *)cp,                  /* Bad passphrase. */
                  (unsigned char *)buffer_ptr(&buffer),                  buffer_free(&decrypted);
                  buffer_len(&buffer));  fail:
                   BN_clear_free(prv->n);
                   BN_clear_free(prv->e);
                   if (comment_return)
                           xfree(*comment_return);
                   return 0;
           }
           /* Read the rest of the private key. */
           prv->d = BN_new();
           buffer_get_bignum(&decrypted, prv->d);
           prv->iqmp = BN_new();
           buffer_get_bignum(&decrypted, prv->iqmp);       /* u */
           /* in SSL and SSH p and q are exchanged */
           prv->q = BN_new();
           buffer_get_bignum(&decrypted, prv->q);          /* p */
           prv->p = BN_new();
           buffer_get_bignum(&decrypted, prv->p);          /* q */
   
   buffer_free(&buffer);          ctx = BN_CTX_new();
           aux = BN_new();
   
   check1 = buffer_get_char(&decrypted);          BN_sub(aux, prv->q, BN_value_one());
   check2 = buffer_get_char(&decrypted);          prv->dmq1 = BN_new();
   if (check1 != buffer_get_char(&decrypted) ||          BN_mod(prv->dmq1, prv->d, aux, ctx);
       check2 != buffer_get_char(&decrypted))  
     {  
       if (strcmp(passphrase, "") != 0)  
         debug("Bad passphrase supplied for key file %.200s.", filename);  
       /* Bad passphrase. */  
       buffer_free(&decrypted);  
     fail:  
       BN_clear_free(prv->n);  
       BN_clear_free(prv->e);  
       if (comment_return)  
         xfree(*comment_return);  
       return 0;  
     }  
   
   /* Read the rest of the private key. */          BN_sub(aux, prv->p, BN_value_one());
   prv->d = BN_new();          prv->dmp1 = BN_new();
   buffer_get_bignum(&decrypted, prv->d);          BN_mod(prv->dmp1, prv->d, aux, ctx);
   prv->iqmp = BN_new();  
   buffer_get_bignum(&decrypted, prv->iqmp); /* u */  
   /* in SSL and SSH p and q are exchanged */  
   prv->q = BN_new();  
   buffer_get_bignum(&decrypted, prv->q); /* p */  
   prv->p = BN_new();  
   buffer_get_bignum(&decrypted, prv->p); /* q */  
   
   ctx = BN_CTX_new();          BN_clear_free(aux);
   aux = BN_new();          BN_CTX_free(ctx);
   
   BN_sub(aux, prv->q, BN_value_one());          buffer_free(&decrypted);
   prv->dmq1 = BN_new();  
   BN_mod(prv->dmq1, prv->d, aux, ctx);  
   
   BN_sub(aux, prv->p, BN_value_one());          return 1;
   prv->dmp1 = BN_new();  
   BN_mod(prv->dmp1, prv->d, aux, ctx);  
   
   BN_clear_free(aux);  
   BN_CTX_free(ctx);  
   
   buffer_free(&decrypted);  
   
   return 1;  
 }  }

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8