Skip to content

Commit 30dd916

Browse files
MarkLodatogitster
authored andcommitted
http.c: prompt for SSL client certificate password
If an SSL client certificate is enabled (via http.sslcert or GIT_SSL_CERT), prompt for the certificate password rather than defaulting to OpenSSL's password prompt. This causes the prompt to only appear once each run. Previously, OpenSSL prompted the user *many* times, causing git to be unusable over HTTPS with client-side certificates. Note that the password is stored in memory in the clear while the program is running. This may be a security problem if git crashes and core dumps. The user is always prompted, even if the certificate is not encrypted. This should be fine; unencrypted certificates are rare and a security risk anyway. Signed-off-by: Mark Lodato <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent cb9d398 commit 30dd916

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

http.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ static int curl_ftp_no_epsv;
2727
static const char *curl_http_proxy;
2828
static char *user_name, *user_pass;
2929

30+
#if LIBCURL_VERSION_NUM >= 0x071700
31+
/* Use CURLOPT_KEYPASSWD as is */
32+
#elif LIBCURL_VERSION_NUM >= 0x070903
33+
#define CURLOPT_KEYPASSWD CURLOPT_SSLKEYPASSWD
34+
#else
35+
#define CURLOPT_KEYPASSWD CURLOPT_SSLCERTPASSWD
36+
#endif
37+
38+
static char *ssl_cert_password;
39+
static int ssl_cert_password_required;
40+
3041
static struct curl_slist *pragma_header;
3142

3243
static struct active_request_slot *active_queue_head;
@@ -167,6 +178,22 @@ static void init_curl_http_auth(CURL *result)
167178
}
168179
}
169180

181+
static int has_cert_password(void)
182+
{
183+
if (ssl_cert_password != NULL)
184+
return 1;
185+
if (ssl_cert == NULL || ssl_cert_password_required != 1)
186+
return 0;
187+
/* Only prompt the user once. */
188+
ssl_cert_password_required = -1;
189+
ssl_cert_password = getpass("Certificate Password: ");
190+
if (ssl_cert_password != NULL) {
191+
ssl_cert_password = xstrdup(ssl_cert_password);
192+
return 1;
193+
} else
194+
return 0;
195+
}
196+
170197
static CURL *get_curl_handle(void)
171198
{
172199
CURL *result = curl_easy_init();
@@ -189,6 +216,8 @@ static CURL *get_curl_handle(void)
189216

190217
if (ssl_cert != NULL)
191218
curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
219+
if (has_cert_password())
220+
curl_easy_setopt(result, CURLOPT_KEYPASSWD, ssl_cert_password);
192221
#if LIBCURL_VERSION_NUM >= 0x070902
193222
if (ssl_key != NULL)
194223
curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
@@ -329,8 +358,11 @@ void http_init(struct remote *remote)
329358
if (getenv("GIT_CURL_FTP_NO_EPSV"))
330359
curl_ftp_no_epsv = 1;
331360

332-
if (remote && remote->url && remote->url[0])
361+
if (remote && remote->url && remote->url[0]) {
333362
http_auth_init(remote->url[0]);
363+
if (!prefixcmp(remote->url[0], "https://"))
364+
ssl_cert_password_required = 1;
365+
}
334366

335367
#ifndef NO_CURL_EASY_DUPHANDLE
336368
curl_default = get_curl_handle();
@@ -370,6 +402,13 @@ void http_cleanup(void)
370402
free((void *)curl_http_proxy);
371403
curl_http_proxy = NULL;
372404
}
405+
406+
if (ssl_cert_password != NULL) {
407+
memset(ssl_cert_password, 0, strlen(ssl_cert_password));
408+
free(ssl_cert_password);
409+
ssl_cert_password = NULL;
410+
}
411+
ssl_cert_password_required = 0;
373412
}
374413

375414
struct active_request_slot *get_active_slot(void)

0 commit comments

Comments
 (0)