2
0
Эх сурвалжийг харах

nss: avoid CURLE_OUT_OF_MEMORY given a file name without any slash

Bug: https://bugzilla.redhat.com/623663
Kamil Dudka 13 жил өмнө
parent
commit
d8f6d1c334

+ 1 - 1
RELEASE-NOTES

@@ -26,7 +26,7 @@ This release includes the following bugfixes:
  o Curl_nss_connect: avoid PATH_MAX
  o Curl_do: avoid using stale conn pointer
  o tftpd test server: avoid buffer overflow report from glibc
- o 
+ o nss: avoid CURLE_OUT_OF_MEMORY given a file name without any slash
 
 This release includes the following known bugs:
 

+ 3 - 2
docs/curl.1

@@ -358,11 +358,12 @@ this option assumes a \&"certificate" file that is the private key and the
 private certificate concatenated! See \fI--cert\fP and \fI--key\fP to specify
 them independently.
 
-If curl is built against the NSS SSL library then this option tells
+If curl is built against the NSS SSL library then this option can tell
 curl the nickname of the certificate to use within the NSS database defined
 by the environment variable SSL_DIR (or by default /etc/pki/nssdb). If the
 NSS PEM PKCS#11 module (libnsspem.so) is available then PEM files may be
-loaded.
+loaded. If you want to use a file from the current directory, please precede
+it with "./" prefix, in order to avoid confusion with a nickname.
 
 If this option is used several times, the last one will be used.
 .IP "--cert-type <type>"

+ 3 - 2
docs/libcurl/curl_easy_setopt.3

@@ -1811,8 +1811,9 @@ Pass a pointer to a zero terminated string as parameter. The string should be
 the file name of your certificate. The default format is "PEM" and can be
 changed with \fICURLOPT_SSLCERTTYPE\fP.
 
-With NSS this is the nickname of the certificate you wish to authenticate
-with.
+With NSS this can also be the nickname of the certificate you wish to
+authenticate with. If you want to use a file from the current directory, please
+precede it with "./" prefix, in order to avoid confusion with a nickname.
 .IP CURLOPT_SSLCERTTYPE
 Pass a pointer to a zero terminated string as parameter. The string should be
 the format of your certificate. Supported formats are "PEM" and "DER".  (Added

+ 40 - 33
lib/nss.c

@@ -277,22 +277,35 @@ static int is_file(const char *filename)
   return 0;
 }
 
-static char *fmt_nickname(char *str, bool *nickname_alloc)
+/* Return on heap allocated filename/nickname of a certificate.  The returned
+ * string should be later deallocated using free().  *is_nickname is set to TRUE
+ * if the given string is treated as nickname; FALSE if the given string is
+ * treated as file name.
+ */
+static char *fmt_nickname(struct SessionHandle *data, enum dupstring cert_kind,
+                          bool *is_nickname)
 {
-  char *nickname = NULL;
-  *nickname_alloc = FALSE;
-
-  if(is_file(str)) {
-    char *n = strrchr(str, '/');
-    if(n) {
-      *nickname_alloc = TRUE;
-      n++; /* skip last slash */
-      nickname = aprintf("PEM Token #%d:%s", 1, n);
-    }
-    return nickname;
+  const char *str = data->set.str[cert_kind];
+  const char *n;
+  *is_nickname = TRUE;
+
+  if(!is_file(str))
+    /* no such file exists, use the string as nickname */
+    return strdup(str);
+
+  /* search the last slash; we require at least one slash in a file name */
+  n = strrchr(str, '/');
+  if(!n) {
+    infof(data, "warning: certificate file name \"%s\" handled as nickname; "
+          "please use \"./%s\" to force file name\n", str, str);
+    return strdup(str);
   }
 
-  return str;
+  /* we'll use the PEM reader to read the certificate from file */
+  *is_nickname = FALSE;
+
+  n++; /* skip last slash */
+  return aprintf("PEM Token #%d:%s", 1, n);
 }
 
 static int nss_load_cert(struct ssl_connect_data *ssl,
@@ -1304,25 +1317,20 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
   }
 
   if(data->set.str[STRING_CERT]) {
-    bool nickname_alloc = FALSE;
-    char *nickname = fmt_nickname(data->set.str[STRING_CERT], &nickname_alloc);
+    bool is_nickname;
+    char *nickname = fmt_nickname(data, STRING_CERT, &is_nickname);
     if(!nickname)
       return CURLE_OUT_OF_MEMORY;
 
-    if(!cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
-                   data->set.str[STRING_KEY])) {
+    if(!is_nickname && !cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
+                                   data->set.str[STRING_KEY])) {
       /* failf() is already done in cert_stuff() */
-      if(nickname_alloc)
-        free(nickname);
+      free(nickname);
       return CURLE_SSL_CERTPROBLEM;
     }
 
-    /* this "takes over" the pointer to the allocated name or makes a
-       dup of it */
-    connssl->client_nickname = nickname_alloc?nickname:strdup(nickname);
-    if(!connssl->client_nickname)
-      return CURLE_OUT_OF_MEMORY;
-
+    /* store the nickname for SelectClientCert() called during handshake */
+    connssl->client_nickname = nickname;
   }
   else
     connssl->client_nickname = NULL;
@@ -1376,18 +1384,17 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
   display_conn_info(conn, connssl->handle);
 
   if (data->set.str[STRING_SSL_ISSUERCERT]) {
-    SECStatus ret;
-    bool nickname_alloc = FALSE;
-    char *nickname = fmt_nickname(data->set.str[STRING_SSL_ISSUERCERT],
-                                  &nickname_alloc);
-
+    SECStatus ret = SECFailure;
+    bool is_nickname;
+    char *nickname = fmt_nickname(data, STRING_SSL_ISSUERCERT, &is_nickname);
     if(!nickname)
       return CURLE_OUT_OF_MEMORY;
 
-    ret = check_issuer_cert(connssl->handle, nickname);
+    if(is_nickname)
+      /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */
+      ret = check_issuer_cert(connssl->handle, nickname);
 
-    if(nickname_alloc)
-      free(nickname);
+    free(nickname);
 
     if(SECFailure == ret) {
       infof(data,"SSL certificate issuer check failed\n");