Support pkcs11 token insertion request and pin input

Note: IDS_NFO_TOKEN_PASSWORD_CAPTION and IDS_NFO_TOKEN_PASSWORD_REQUEST
strings need translation.

TODO: support for selecting pkcs11-id from the GUI

Signed-off-by: Selva Nair <selva.nair@gmail.com>
pull/91/head
Selva Nair 8 years ago
parent 1a5ce44a99
commit be417bb38f

@ -116,6 +116,8 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance,
{ password, OnPassword },
{ proxy, OnProxy },
{ stop, OnStop },
{ needok, OnNeedOk },
{ needstr, OnNeedStr },
{ 0, NULL }
};
InitManagement(handler);

@ -312,6 +312,16 @@ OnManagement(SOCKET sk, LPARAM lParam)
if (rtmsg_handler[ready])
rtmsg_handler[ready](c, pos + 5);
}
else if (strncmp(pos, "NEED-OK:", 8) == 0)
{
if (rtmsg_handler[needok])
rtmsg_handler[needok](c, pos + 8);
}
else if (strncmp(pos, "NEED-STR:", 9) == 0)
{
if (rtmsg_handler[needstr])
rtmsg_handler[needstr](c, pos + 9);
}
}
else if (c->manage.cmd_queue)
{

@ -301,7 +301,12 @@
/* Save password related messages */
#define IDS_NFO_DELETE_PASS 2001
/* Token password dialog related */
#define IDS_NFO_TOKEN_PASSWORD_CAPTION 2100
#define IDS_NFO_TOKEN_PASSWORD_REQUEST 2101
/* Timer IDs */
#define IDT_STOP_TIMER 2500 /* Timer used to trigger force termination */
#endif

@ -63,6 +63,10 @@ const TCHAR *cfgProp = _T("conn");
#define FLAG_CR_TYPE_CRV1 0x2 /* dynamic challenege */
#define FLAG_CR_ECHO 0x4 /* echo the response */
#define FLAG_CR_RESPONSE 0x8 /* response needed */
#define FLAG_PASS_TOKEN 0x10 /* PKCS11 token password needed */
#define FLAG_STRING_PKCS11 0x20 /* PKCS11 id needed */
#define FLAG_PASS_PKEY 0x40 /* Private key password needed */
typedef struct {
connection_t *c;
unsigned int flags;
@ -395,6 +399,16 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
if (param->flags & FLAG_CR_ECHO)
SendMessage(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), EM_SETPASSWORDCHAR, 0, 0);
}
else if (param->flags & FLAG_PASS_TOKEN)
{
SetWindowText(hwndDlg, LoadLocalizedString(IDS_NFO_TOKEN_PASSWORD_CAPTION));
SetDlgItemText(hwndDlg, ID_TXT_DESCRIPTION, LoadLocalizedString(IDS_NFO_TOKEN_PASSWORD_REQUEST, param->id));
}
else
{
WriteStatusLog(param->c, L"GUI> ", L"Unknown password request", false);
SetDlgItemText(hwndDlg, ID_TXT_DESCRIPTION, wstr);
}
free(wstr);
AppendTextToCaption (hwndDlg, param->c->config_name);
@ -407,14 +421,17 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_COMMAND:
param = (auth_param_t *) GetProp(hwndDlg, cfgProp);
const char *template;
char *fmt;
switch (LOWORD(wParam))
{
case IDOK:
if (param->flags & FLAG_CR_TYPE_CRV1)
{
/* send username */
const char *template = "username \"Auth\" \"%s\"";
char *fmt = malloc(strlen(template) + strlen(param->user));
template = "username \"Auth\" \"%s\"";
fmt = malloc(strlen(template) + strlen(param->user));
if (fmt)
{
sprintf(fmt, template, param->user);
@ -424,31 +441,33 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
else /* no memory? send an emty username and let it error out */
{
WriteStatusLog(param->c, L"GUI> ",
L"Out of memory: sending empty username for dynamic CR", false);
L"Out of memory: sending a generic username for dynamic CR", false);
ManagementCommand(param->c, "username \"Auth\" \"user\"", NULL, regular);
}
/* send password */
/* password template */
template = "password \"Auth\" \"CRV1::%s::%%s\"";
fmt = malloc(strlen(template) + strlen(param->id));
if (fmt)
{
sprintf(fmt, template, param->id);
ManagementCommandFromInput(param->c, fmt, hwndDlg, ID_EDT_RESPONSE);
free (fmt);
}
else /* no memory? send an empty password and let it error out. */
{
WriteStatusLog(param->c, L"GUI> ",
L"Out of memory: sending empty password for dynamic CR", false);
ManagementCommand(param->c, "password \"Auth\" \"CRV1::0::\"", NULL, regular);
}
}
else
else /* generic password request of type param->id */
{
template = "password \"%s\" \"%%s\"";
}
fmt = malloc(strlen(template) + strlen(param->id));
if (fmt)
{
sprintf(fmt, template, param->id);
PrintDebug(L"Send passwd to mgmt with format: '%S'", fmt);
ManagementCommandFromInput(param->c, fmt, hwndDlg, ID_EDT_RESPONSE);
free (fmt);
}
else /* no memory? send stop signal */
{
/* Unknown request ? */
WriteStatusLog(param->c, L"GUI> ", L"Unknown password reuest ignored", false);
WriteStatusLog(param->c, L"GUI> ",
L"Out of memory in password dialog: sending stop signal", false);
StopOpenVPN (param->c);
}
EndDialog(hwndDlg, LOWORD(wParam));
return TRUE;
@ -607,6 +626,69 @@ out:
return ret;
}
/*
* Parse password or string request of the form "Need 'What' password/string MSG:message"
* and assign param->id = What, param->str = message. Also set param->flags if the type
* of the requested info is known. If message is empty param->id is copied to param->str.
* Return true on succsess. The caller must free param even when the function fails.
*/
static BOOL
parse_input_request (const char *msg, auth_param_t *param)
{
BOOL ret = FALSE;
char *p = strdup (msg);
char *sep[4] = {" ", "'", " ", ""}; /* separators to use to break up msg */
char *token[4];
char *p1 = p;
for (int i = 0; i < 4; ++i, p1 = NULL)
{
token[i] = strtok (p1, sep[i]); /* strtok is thread-safe on Windows */
if (!token[i] && i < 3) /* first three tokens required */
goto out;
}
if (token[3] && strncmp(token[3], "MSG:", 4) == 0)
token[3] += 4;
if (!token[3] || !*token[3]) /* use id as the description if none provided */
token[3] = token[1];
PrintDebug (L"Tokens: '%S' '%S' '%S' '%S'", token[0], token[1],
token[2], token[3]);
if (strcmp (token[0], "Need") != 0)
goto out;
if ((param->id = strdup(token[1])) == NULL)
goto out;
if (strcmp(token[2], "password") == 0)
{
if (strcmp (param->id, "Private Key") == 0)
param->flags |= FLAG_PASS_PKEY;
else
param->flags |= FLAG_PASS_TOKEN;
}
else if (strcmp(token[2], "string") == 0
&& strcmp (param->id, "pkcs11-id-request") == 0)
{
param->flags |= FLAG_STRING_PKCS11;
}
param->str = strdup (token[3]);
if (param->str == NULL)
goto out;
PrintDebug (L"parse_input_request: id = '%S' str = '%S' flags = %u",
param->id, param->str, param->flags);
ret = TRUE;
out:
free (p);
if (!ret)
PrintDebug (L"Error parsing password/string request msg: <%S>", msg);
return ret;
}
/*
* Handle >PASSWORD: request from OpenVPN management interface
*/
@ -690,6 +772,24 @@ OnPassword(connection_t *c, char *msg)
{
QueryProxyAuth(c, socks);
}
/* All other password requests such as PKCS11 pin */
else if (strncmp(msg, "Need '", 6) == 0)
{
auth_param_t *param = (auth_param_t *) calloc(1, sizeof(auth_param_t));
if (!param)
{
WriteStatusLog (c, L"GUI> ", L"Error: Out of memory - ignoring user-auth request", false);
return;
}
param->c = c;
if (!parse_input_request (msg, param))
{
free_auth_param(param);
return;
}
LocalizedDialogBoxParam(ID_DLG_CHALLENGE_RESPONSE, GenericPassDialogFunc, (LPARAM) param);
}
}
@ -1047,6 +1147,65 @@ OnProcess (connection_t *c, UNUSED char *msg)
OnStop (c, NULL);
}
/*
* Called when NEED-OK is received
*/
void
OnNeedOk (connection_t *c, char *msg)
{
char *resp = NULL;
WCHAR *wstr = NULL;
auth_param_t *param = (auth_param_t *) calloc(1, sizeof(auth_param_t));
if (!param)
{
WriteStatusLog(c, L"GUI> ", L"Error: out of memory while processing NEED-OK. Sending stop signal", false);
StopOpenVPN(c);
return;
}
if (!parse_input_request(msg, param))
goto out;
/* allocate space for response : "needok param->id cancel/ok" */
resp = malloc (strlen(param->id) + strlen("needok \' \' cancel"));
wstr = Widen(param->str);
if (!wstr || !resp)
{
WriteStatusLog(c, L"GUI> ", L"Error: out of memory while processing NEED-OK. Sending stop signal", false);
StopOpenVPN(c);
goto out;
}
const char *fmt;
if (MessageBoxW (NULL, wstr, L""PACKAGE_NAME, MB_OKCANCEL) == IDOK)
{
fmt = "needok \'%s\' ok";
}
else
{
ManagementCommand (c, "auth-retry none", NULL, regular);
fmt = "needok \'%s\' cancel";
}
sprintf (resp, fmt, param->id);
ManagementCommand (c, resp, NULL, regular);
out:
free_auth_param (param);
free(wstr);
free(resp);
}
/*
* Called when NEED-STR is received
*/
void
OnNeedStr (connection_t *c, UNUSED char *msg)
{
WriteStatusLog (c, L"GUI> ", L"Error: Received NEED-STR message -- not implemented", false);
}
/*
* Close open handles
*/

@ -35,6 +35,8 @@ void OnLogLine(connection_t *, char *);
void OnStateChange(connection_t *, char *);
void OnPassword(connection_t *, char *);
void OnStop(connection_t *, char *);
void OnNeedOk(connection_t *, char *);
void OnNeedStr(connection_t *, char *);
void DisablePasswordSave(connection_t *);

@ -84,8 +84,8 @@ typedef struct {
} service_io_t;
#define FLAG_ALLOW_CHANGE_PASSPHRASE (1<<1)
#define FLAG_SAVE_KEY_PASS 1<<4
#define FLAG_SAVE_AUTH_PASS 1<<5
#define FLAG_SAVE_KEY_PASS (1<<4)
#define FLAG_SAVE_AUTH_PASS (1<<5)
typedef struct {
unsigned short major, minor, build, revision;

@ -448,4 +448,9 @@ BEGIN
/* save/delete password */
IDS_NFO_DELETE_PASS "Press OK to delete saved passwords for config ""%s"""
/* Token password related */
IDS_NFO_TOKEN_PASSWORD_CAPTION "OpenVPN - Token Password"
IDS_NFO_TOKEN_PASSWORD_REQUEST "Input Password/PIN for Token '%S'"
END

Loading…
Cancel
Save