added support for %prompt-ing private key passhprases in strokes "ipsec secrets"
authorMartin Willi <martin@strongswan.org>
Fri, 14 Aug 2009 13:01:35 +0000 (15:01 +0200)
committerMartin Willi <martin@strongswan.org>
Wed, 26 Aug 2009 09:23:50 +0000 (11:23 +0200)
src/charon/plugins/stroke/stroke_cred.c
src/charon/plugins/stroke/stroke_cred.h
src/charon/plugins/stroke/stroke_socket.c
src/stroke/stroke.c

index 43046b1..80ca177 100644 (file)
@@ -729,9 +729,54 @@ static err_t extract_secret(chunk_t *secret, chunk_t *line)
 }
 
 /**
+ * Data to pass to passphrase_cb
+ */
+typedef struct {
+       /** socket we use for prompting */
+       FILE *prompt;
+       /** private key file */
+       char *file;
+       /** buffer for passphrase */
+       char buf[256];
+} passphrase_cb_data_t;
+
+/**
+ * Passphrase callback to read from whack fd
+ */
+chunk_t passphrase_cb(passphrase_cb_data_t *data, int try)
+{
+       chunk_t secret = chunk_empty;;
+       
+       if (try > 5)
+       {
+               fprintf(data->prompt, "invalid passphrase, too many trials\n");
+               return chunk_empty;
+       }
+       if (try == 1)
+       {
+               fprintf(data->prompt, "Private key '%s' is encrypted\n", data->file);
+       }
+       else
+       {
+               fprintf(data->prompt, "invalid passphrase\n");
+       }
+       fprintf(data->prompt, "Passphrase:\n");
+       if (fgets(data->buf, sizeof(data->buf), data->prompt))
+       {
+               secret = chunk_create(data->buf, strlen(data->buf));
+               if (secret.len)
+               {       /* trim appended \n */
+                       secret.len--;
+               }
+       }
+       return secret;
+}
+
+/**
  * reload ipsec.secrets
  */
-static void load_secrets(private_stroke_cred_t *this, char *file, int level)
+static void load_secrets(private_stroke_cred_t *this, char *file, int level,
+                                                FILE *prompt)
 {
        size_t bytes;
        int line_nr = 0;
@@ -838,7 +883,7 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level)
                        {
                                for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
                                {
-                                       load_secrets(this, *expanded, level + 1);
+                                       load_secrets(this, *expanded, level + 1, prompt);
                                }
                        }
                        globfree(&buf);
@@ -873,7 +918,7 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level)
                        char path[PATH_MAX];
                        chunk_t filename;
                        chunk_t secret = chunk_empty;
-                       private_key_t *key;
+                       private_key_t *key = NULL;
                        key_type_t key_type = match("RSA", &token) ? KEY_RSA : KEY_ECDSA;
 
                        err_t ugh = extract_value(&filename, &line);
@@ -910,15 +955,36 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level)
                                        goto error;
                                }
                        }
-                       key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
-                                                                        BUILD_FROM_FILE, path,
-                                                                        BUILD_PASSPHRASE, secret,BUILD_END);
+                       if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
+                       {
+                               if (prompt)
+                               {
+                                       passphrase_cb_data_t data;
+                                       
+                                       data.prompt = prompt;
+                                       data.file = path;
+                                       key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+                                                                                        key_type, BUILD_FROM_FILE, path,
+                                                                                        BUILD_PASSPHRASE_CALLBACK,
+                                                                                        passphrase_cb, &data, BUILD_END);
+                               }
+                       }
+                       else
+                       {
+                               key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
+                                                                                BUILD_FROM_FILE, path,
+                                                                                BUILD_PASSPHRASE, secret, BUILD_END);
+                       }
                        if (key)
                        {
                                DBG1(DBG_CFG, "  loaded %N private key file '%s'",
                                         key_type_names, key->get_type(key), path);
                                this->private->insert_last(this->private, key);
                        }
+                       else
+                       {
+                               DBG1(DBG_CFG, "  skipped private key file '%s'", path);
+                       }
                        chunk_clear(&secret);
                }
                else if (match("PIN", &token))
@@ -1083,12 +1149,12 @@ static void load_certs(private_stroke_cred_t *this)
 /**
  * Implementation of stroke_cred_t.reread.
  */
-static void reread(private_stroke_cred_t *this, stroke_msg_t *msg)
+static void reread(private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt)
 {
        if (msg->reread.flags & REREAD_SECRETS)
        {
                DBG1(DBG_CFG, "rereading secrets");
-               load_secrets(this, SECRETS_FILE, 0);
+               load_secrets(this, SECRETS_FILE, 0, prompt);
        }
        if (msg->reread.flags & REREAD_CACERTS)
        {
@@ -1147,7 +1213,7 @@ stroke_cred_t *stroke_cred_create()
        this->public.set.create_shared_enumerator = (void*)create_shared_enumerator;
        this->public.set.create_cdp_enumerator = (void*)return_null;
        this->public.set.cache_cert = (void*)cache_cert;
-       this->public.reread = (void(*)(stroke_cred_t*, stroke_msg_t *msg))reread;
+       this->public.reread = (void(*)(stroke_cred_t*, stroke_msg_t *msg, FILE*))reread;
        this->public.load_ca = (certificate_t*(*)(stroke_cred_t*, char *filename))load_ca;
        this->public.load_peer = (certificate_t*(*)(stroke_cred_t*, char *filename))load_peer;
        this->public.cachecrl = (void(*)(stroke_cred_t*, bool enabled))cachecrl;
@@ -1159,7 +1225,7 @@ stroke_cred_t *stroke_cred_create()
        this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
 
        load_certs(this);
-       load_secrets(this, SECRETS_FILE, 0);
+       load_secrets(this, SECRETS_FILE, 0, NULL);
        
        this->cachecrl = FALSE;
        
index 8bc042f..3924ccb 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef STROKE_CRED_H_
 #define STROKE_CRED_H_
 
+#include <stdio.h>
+
 #include <stroke_msg.h>
 #include <credentials/credential_set.h>
 #include <credentials/certificates/certificate.h>
@@ -41,8 +43,9 @@ struct stroke_cred_t {
         * Reread secrets from config files.
         *
         * @param msg           stroke message
+        * @param prompt        I/O channel to prompt for private key passhprase
         */
-       void (*reread)(stroke_cred_t *this, stroke_msg_t *msg);
+       void (*reread)(stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt);
        
        /**
         * Load a CA certificate, and serve it through the credential_set.
@@ -68,9 +71,9 @@ struct stroke_cred_t {
        void (*cachecrl)(stroke_cred_t *this, bool enabled);
        
        /**
-     * Destroy a stroke_cred instance.
-     */
-    void (*destroy)(stroke_cred_t *this);
+        * Destroy a stroke_cred instance.
+        */
+       void (*destroy)(stroke_cred_t *this);
 };
 
 /**
index 9b6a8a3..f420266 100644 (file)
@@ -333,7 +333,7 @@ static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *
 static void stroke_reread(private_stroke_socket_t *this,
                                                  stroke_msg_t *msg, FILE *out)
 {
-       this->cred->reread(this->cred, msg);
+       this->cred->reread(this->cred, msg, out);
 }
 
 /**
@@ -467,7 +467,7 @@ static job_requeue_t process(stroke_job_context_t *ctx)
                return JOB_REQUEUE_NONE;
        }
        
-       out = fdopen(strokefd, "w");
+       out = fdopen(strokefd, "w+");
        if (out == NULL)
        {
                DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
index c27a8ca..186e480 100644 (file)
@@ -55,7 +55,7 @@ static int send_stroke_msg (stroke_msg_t *msg)
 {
        struct sockaddr_un ctl_addr;
        int sock;
-       char buffer[64];
+       char buffer[512];
        int byte_count;
 
        ctl_addr.sun_family = AF_UNIX;
@@ -89,6 +89,16 @@ static int send_stroke_msg (stroke_msg_t *msg)
        {
                buffer[byte_count] = '\0';
                printf("%s", buffer);
+               
+               /* we prompt if we receive the "Passphrase:" magic keyword */
+               if (byte_count >= 12 &&
+                       strcmp(buffer + byte_count - 12, "Passphrase:\n") == 0)
+               {
+                       if (fgets(buffer, sizeof(buffer), stdin))
+                       {
+                               if (write(sock, buffer, strlen(buffer)));
+                       }
+               }
        }
        if (byte_count < 0)
        {