@matheusbsbs / matheus-bagliano / commits / 30dd916348
Fork 0

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 <lodatom@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Mark Lodato committed May 27, 2009 at 23:16 UTC 30dd916348001e4313708473d91d633d3b14d1b5
1 file changed +40 -1
http.c
+40 -1
@@ -27,6 +27,17 @@ static int curl_ftp_no_epsv;
27 static const char *curl_http_proxy;
28 static char *user_name, *user_pass;
29
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 +
41 static struct curl_slist *pragma_header;
42
43 static struct active_request_slot *active_queue_head;
@@ -167,6 +178,22 @@ static void init_curl_http_auth(CURL *result)
178 }
179 }
180
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 +
197 static CURL *get_curl_handle(void)
198 {
199 CURL *result = curl_easy_init();
@@ -189,6 +216,8 @@ static CURL *get_curl_handle(void)
216
217 if (ssl_cert != NULL)
218 curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
219 + if (has_cert_password())
220 + curl_easy_setopt(result, CURLOPT_KEYPASSWD, ssl_cert_password);
221 #if LIBCURL_VERSION_NUM >= 0x070902
222 if (ssl_key != NULL)
223 curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
@@ -329,8 +358,11 @@ void http_init(struct remote *remote)
358 if (getenv("GIT_CURL_FTP_NO_EPSV"))
359 curl_ftp_no_epsv = 1;
360
332 - if (remote && remote->url && remote->url[0])
361 + if (remote && remote->url && remote->url[0]) {
362 http_auth_init(remote->url[0]);
363 + if (!prefixcmp(remote->url[0], "https://"))
364 + ssl_cert_password_required = 1;
365 + }
366
367 #ifndef NO_CURL_EASY_DUPHANDLE
368 curl_default = get_curl_handle();
@@ -370,6 +402,13 @@ void http_cleanup(void)
402 free((void *)curl_http_proxy);
403 curl_http_proxy = NULL;
404 }
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;
412 }
413
414 struct active_request_slot *get_active_slot(void)