SSH_ASKPASSを取り扱う方法を考える
Emacsから ssh-add -
を使い標準入力に鍵を渡そうとした時、その鍵にパスフレーズが設定されている場合、パスフレーズを渡す手段が必要になる。tty経由で渡したかったけれど、上手く渡す事ができなかったため、仕方がないからファイル経由で渡す事にした。
ただしパスフレーズは重要な値だから、暗号化して保存する。
askpass.el
;;; askpass --- askpass utility -*- lexical-binding: t -*-
;; Copyright (C) 2023 TakesxiSximada
;; Author: TakesxiSximada <[email protected]>
;; Maintainer: TakesxiSximada <[email protected]>
;; Repository:
;; Version: 1
;; Package-Version: 20240224.0000
;; Package-Requires: ((emacs "28.0")
;; Date: 2024-02-24
;; This file is part of askpass.el.
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program 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 General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(defvar askpass-delete-timer nil)
(defcustom askpass-file "~/.askpass.gpg"
"File for storing encrypted temporary values"
:type 'string
:group 'askpass)
(defcustom askpass-file "~/.askpass.gpg"
"File for storing encrypted temporary values"
:type 'string
:group 'askpass)
(defcustom askpass-program nil
"askpass.el acquisition program"
:type 'string
:group 'askpass)
(defcustom askpass-recipient nil
"Owner of the key used for encryption with GnuPG"
:type 'string
:group 'askpass)
(defun askpass-activate ()
(interactive)
(setenv "ASKPASS_GPG_FILE" (expand-file-name askpass-file))
(setenv "SSH_ASKPASS" askpass-program))
(defun askpass-delete-file ()
(message (format "File deleting...: %s" askpass-file))
(delete-file askpass-file)
(message (format "File deleted: %s" askpass-file))
(setq askpass-delete-timer nil))
(defun askpass-set-delete-timer ()
(interactive)
(unless askpass-delete-timer
(setq askpass-delete-timer
(run-at-time "10 sec" nil #'askpass-delete-file))))
(defun askpass-format-gpg-command ()
(format "gpg --encrypt -r %s" askpass-recipient))
(defun askpass ()
(interactive)
(let* ((output-path (expand-file-name askpass-file))
(output-buf (create-file-buffer output-path)))
(with-current-buffer output-buf
(set-visited-file-name (expand-file-name output-path))
(set-buffer-file-coding-system 'raw-text)
(erase-buffer)
(let ((file-name-handler-alist nil))
(save-buffer)))
(with-temp-buffer
(insert (password-read "SSH Agent Passphase: "))
(shell-command-on-region (point-min) (point-max)
(askpass-format-gpg-command)
output-buf))
(with-current-buffer output-buf
(let ((file-name-handler-alist nil))
(save-buffer)
(kill-buffer))))
(askpass-activate)
(askpass-set-delete-timer))
(defun askpass-show ()
(interactive)
(shell-command askpass-file))
(provide 'askpass)
;;; askpass.el ends here
取得用のプログラムのスクリプトは、単純にGnuPGを実行するだけだ。
askpass-gpg
#! /usr/local/bin/bash
exec gpg --decrypt ${ASKPASS_GPG_FILE}
正しい方法はありそうだけれど、とりえずこれでお茶を濁す。