+
+ check1 = buffer_get_char(&decrypted);
+ check2 = buffer_get_char(&decrypted);
+ if (check1 != buffer_get_char(&decrypted) ||
+ check2 != buffer_get_char(&decrypted)) {
+ if (strcmp(passphrase, "") != 0)
+ debug("Bad passphrase supplied for key file %.200s.",
+ filename);
+ /* Bad passphrase. */
+ buffer_free(&decrypted);
+ goto fail;
+ }
+ /* Read the rest of the private key. */
+ buffer_get_bignum(&decrypted, prv->rsa->d);
+ buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
+ /* in SSL and SSH v1 p and q are exchanged */
+ buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
+ buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
+
+ /* calculate p-1 and q-1 */
+ rsa_generate_additional_parameters(prv->rsa);
+
+ buffer_free(&decrypted);
+
+ /* enable blinding */
+ if (RSA_blinding_on(prv->rsa, NULL) != 1) {
+ error("key_load_private_rsa1: RSA_blinding_on failed");
+ goto fail;
+ }
+ close(fd);
+ return prv;
+
+fail:
+ if (commentp)
+ xfree(*commentp);
+ close(fd);
+ key_free(prv);
+ return NULL;
+}
+
+Key *
+key_load_private_pem(int fd, int type, const char *passphrase,
+ char **commentp)
+{
+ FILE *fp;
+ EVP_PKEY *pk = NULL;
+ Key *prv = NULL;
+ char *name = "<no key>";
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ error("fdopen failed: %s", strerror(errno));
+ close(fd);
+ return NULL;
+ }
+ pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase);
+ if (pk == NULL) {
+ debug("PEM_read_PrivateKey failed");
+ (void)ERR_get_error();
+ } else if (pk->type == EVP_PKEY_RSA &&
+ (type == KEY_UNSPEC||type==KEY_RSA)) {
+ prv = key_new(KEY_UNSPEC);
+ prv->rsa = EVP_PKEY_get1_RSA(pk);
+ prv->type = KEY_RSA;
+ name = "rsa w/o comment";
+#ifdef DEBUG_PK
+ RSA_print_fp(stderr, prv->rsa, 8);
+#endif
+ if (RSA_blinding_on(prv->rsa, NULL) != 1) {
+ error("key_load_private_pem: RSA_blinding_on failed");
+ key_free(prv);
+ prv = NULL;
+ }
+ } else if (pk->type == EVP_PKEY_DSA &&
+ (type == KEY_UNSPEC||type==KEY_DSA)) {
+ prv = key_new(KEY_UNSPEC);
+ prv->dsa = EVP_PKEY_get1_DSA(pk);
+ prv->type = KEY_DSA;
+ name = "dsa w/o comment";
+#ifdef DEBUG_PK
+ DSA_print_fp(stderr, prv->dsa, 8);
+#endif
+ } else {
+ error("PEM_read_PrivateKey: mismatch or "
+ "unknown EVP_PKEY save_type %d", pk->save_type);
+ }
+ fclose(fp);
+ if (pk != NULL)
+ EVP_PKEY_free(pk);
+ if (prv != NULL && commentp)
+ *commentp = xstrdup(name);
+ debug("read PEM private key done: type %s",
+ prv ? key_type(prv) : "<unknown>");
+ return prv;
+}
+
+int
+key_perm_ok(int fd, const char *filename)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ return 0;
+ /*
+ * if a key owned by the user is accessed, then we check the
+ * permissions of the file. if the key owned by a different user,
+ * then we don't care.
+ */
+#ifdef HAVE_CYGWIN
+ if (check_ntsec(filename))
+#endif
+ if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
+ error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
+ error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ error("Permissions 0%3.3o for '%s' are too open.",
+ (u_int)st.st_mode & 0777, filename);
+ error("It is recommended that your private key files are NOT accessible by others.");
+ error("This private key will be ignored.");
+ return 0;
+ }
+ return 1;
+}
+
+Key *
+key_load_private_type(int type, const char *filename, const char *passphrase,
+ char **commentp, int *perm_ok)
+{
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ debug("could not open key file '%s': %s", filename,
+ strerror(errno));
+ if (perm_ok != NULL)
+ *perm_ok = 0;
+ return NULL;
+ }
+ if (!key_perm_ok(fd, filename)) {
+ if (perm_ok != NULL)
+ *perm_ok = 0;
+ error("bad permissions: ignore key: %s", filename);
+ close(fd);
+ return NULL;
+ }
+ if (perm_ok != NULL)
+ *perm_ok = 1;
+ switch (type) {
+ case KEY_RSA1:
+ return key_load_private_rsa1(fd, filename, passphrase,
+ commentp);
+ /* closes fd */
+ case KEY_DSA:
+ case KEY_RSA:
+ case KEY_UNSPEC:
+ return key_load_private_pem(fd, type, passphrase, commentp);
+ /* closes fd */
+ default:
+ close(fd);
+ break;
+ }
+ return NULL;
+}
+
+Key *
+key_load_private(const char *filename, const char *passphrase,
+ char **commentp)
+{
+ Key *pub, *prv;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ debug("could not open key file '%s': %s", filename,
+ strerror(errno));
+ return NULL;
+ }
+ if (!key_perm_ok(fd, filename)) {
+ error("bad permissions: ignore key: %s", filename);
+ close(fd);
+ return NULL;
+ }
+ pub = key_load_public_rsa1(fd, filename, commentp);
+ lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
+ if (pub == NULL) {
+ /* closes fd */
+ prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
+ /* use the filename as a comment for PEM */
+ if (commentp && prv)
+ *commentp = xstrdup(filename);
+ } else {
+ /* it's a SSH v1 key if the public key part is readable */
+ key_free(pub);
+ /* closes fd */
+ prv = key_load_private_rsa1(fd, filename, passphrase, NULL);
+ }
+ return prv;
+}
+
+static int
+key_try_load_public(Key *k, const char *filename, char **commentp)
+{
+ FILE *f;
+ char line[SSH_MAX_PUBKEY_BYTES];
+ char *cp;
+ u_long linenum = 0;
+
+ f = fopen(filename, "r");
+ if (f != NULL) {
+ while (read_keyfile_line(f, filename, line, sizeof(line),
+ &linenum) != -1) {
+ cp = line;
+ switch (*cp) {
+ case '#':
+ case '\n':
+ case '\0':
+ continue;
+ }
+ /* Skip leading whitespace. */
+ for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
+ ;
+ if (*cp) {
+ if (key_read(k, &cp) == 1) {
+ if (commentp)
+ *commentp=xstrdup(filename);
+ fclose(f);
+ return 1;
+ }
+ }
+ }
+ fclose(f);
+ }