LCOV - code coverage report
Current view: top level - mnt/wasteland/wcohen/systemtap_write/systemtap - nsscommon.cxx (source / functions) Hit Total Coverage
Test: stap.info Lines: 332 641 51.8 %
Date: 2013-03-08 Functions: 27 33 81.8 %
Branches: 265 1320 20.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :   Common functions used by the NSS-aware code in systemtap.
       3                 :            : 
       4                 :            :   Copyright (C) 2009-2013 Red Hat Inc.
       5                 :            : 
       6                 :            :   This file is part of systemtap, and is free software.  You can
       7                 :            :   redistribute it and/or modify it under the terms of the GNU General Public
       8                 :            :   License as published by the Free Software Foundation; either version 2 of the
       9                 :            :   License, or (at your option) any later version.
      10                 :            : 
      11                 :            :   This program is distributed in the hope that it will be useful,
      12                 :            :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14                 :            :   GNU General Public License for more details.
      15                 :            : 
      16                 :            :   You should have received a copy of the GNU General Public License
      17                 :            :   along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18                 :            : */
      19                 :            : 
      20                 :            : #include "config.h"
      21                 :            : 
      22                 :            : #include <iostream>
      23                 :            : #include <fstream>
      24                 :            : #include <sstream>
      25                 :            : #include <cerrno>
      26                 :            : #include <cstdio>
      27                 :            : #include <cassert>
      28                 :            : 
      29                 :            : extern "C" {
      30                 :            : #include <time.h>
      31                 :            : #include <termios.h>
      32                 :            : #include <unistd.h>
      33                 :            : #include <glob.h>
      34                 :            : #include <sys/stat.h>
      35                 :            : #include <sys/utsname.h>
      36                 :            : 
      37                 :            : #include <nss.h>
      38                 :            : #include <nspr.h>
      39                 :            : #include <ssl.h>
      40                 :            : #include <prerror.h>
      41                 :            : #include <secerr.h>
      42                 :            : #include <sslerr.h>
      43                 :            : #include <cryptohi.h>
      44                 :            : #include <keyhi.h>
      45                 :            : #include <secder.h>
      46                 :            : }
      47                 :            : 
      48                 :            : #include "nsscommon.h"
      49                 :            : #include "util.h"
      50                 :            : 
      51                 :            : using namespace std;
      52                 :            : 
      53                 :            : // Common constants and settings.
      54                 :            : const char *
      55                 :         68 : server_cert_nickname ()
      56                 :            : {
      57                 :         68 :   return (const char *)"stap-server";
      58                 :            : }
      59                 :            : 
      60                 :            : string
      61                 :         10 : server_cert_db_path ()
      62                 :            : {
      63         [ +  - ]:         10 :   string data_path;
      64                 :         10 :   const char* s_d = getenv ("SYSTEMTAP_DIR");
      65         [ +  - ]:         10 :   if (s_d != NULL)
      66         [ +  - ]:         10 :     data_path = s_d;
      67                 :            :   else
      68 [ #  # ][ #  # ]:          0 :     data_path = get_home_directory() + string("/.systemtap");
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      69 [ +  - ][ +  - ]:         10 :   return data_path + "/ssl/server";
      70                 :            : }
      71                 :            : 
      72                 :            : string
      73                 :         99 : local_client_cert_db_path ()
      74                 :            : {
      75         [ +  - ]:         99 :   string data_path;
      76                 :         99 :   const char* s_d = getenv ("SYSTEMTAP_DIR");
      77         [ +  - ]:         99 :   if (s_d != NULL)
      78         [ +  - ]:         99 :     data_path = s_d;
      79                 :            :   else
      80 [ #  # ][ #  # ]:          0 :     data_path = get_home_directory() + string("/.systemtap");
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      81 [ +  - ][ +  - ]:         99 :   return data_path + "/ssl/client";
      82                 :            : }
      83                 :            : 
      84                 :            : // Common error handling for applications using this file.
      85                 :            : void
      86                 :          0 : nsscommon_error (const string &msg, int logit)
      87                 :            : {
      88                 :            :   // Call the extern "C" version supplied by each application.
      89                 :          0 :   nsscommon_error (msg.c_str (), logit);
      90                 :          0 : }
      91                 :            : 
      92                 :            : // Logging. Enabled only by stap-serverd but called from some common methods.
      93                 :       2938 : static ofstream logfile;
      94                 :            : 
      95                 :            : void
      96                 :          5 : start_log (const char *arg)
      97                 :            : {
      98         [ -  + ]:          5 :   if (logfile.is_open ())
      99                 :          0 :     logfile.close ();
     100                 :            : 
     101                 :          5 :   logfile.open (arg, ios_base::app);
     102         [ -  + ]:          5 :   if (! logfile.good ())
     103         [ #  # ]:          0 :     nsscommon_error (_F("Could not open log file %s", arg));
     104                 :          5 : }
     105                 :            : 
     106                 :            : bool
     107                 :          5 : log_ok ()
     108                 :            : {
     109                 :          5 :   return logfile.good ();
     110                 :            : }
     111                 :            : 
     112                 :            : void
     113                 :        201 : log (const string &msg)
     114                 :            : {
     115                 :            :   // What time is it?
     116                 :            :   time_t now;
     117                 :        201 :   time (& now);
     118         [ +  - ]:        201 :   string nowStr = ctime (& now);
     119                 :            :   // Remove the newline from the end of the time string.
     120 [ +  - ][ +  - ]:        201 :   nowStr.erase (nowStr.size () - 1, 1);
     121                 :            : 
     122 [ +  - ][ +  - ]:        201 :   if (logfile.good ())
     123 [ +  - ][ +  - ]:        201 :     logfile << nowStr << ": " << msg << endl << flush;
         [ +  - ][ +  - ]
                 [ +  - ]
     124                 :            :   else
     125 [ #  # ][ #  # ]:        201 :     clog << nowStr << ": " << msg << endl << flush;
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
     126                 :        201 : }
     127                 :            : 
     128                 :            : void
     129                 :          5 : end_log ()
     130                 :            : {
     131         [ +  - ]:          5 :   if (logfile.is_open ())
     132                 :          5 :     logfile.close ();
     133                 :          5 : }
     134                 :            : 
     135                 :            : // NSS/NSPR error reporting and cleanup.
     136                 :            : // These functions are called from C code as well as C++, so make them extern "C".
     137                 :            : extern "C"
     138                 :            : void
     139                 :          0 : nssError (void)
     140                 :            : {
     141                 :            :   // See if PR_GetError can tell us what the error is.
     142                 :          0 :   PRErrorCode errorNumber = PR_GetError ();
     143                 :            : 
     144                 :            :   // PR_ErrorToString always returns a valid string for errors in this range.
     145 [ #  # ][ #  # ]:          0 :   if (errorNumber >= PR_NSPR_ERROR_BASE && errorNumber <= PR_MAX_ERROR)
     146                 :            :     {
     147         [ #  # ]:          0 :       nsscommon_error (_F("(%d) %s", errorNumber, PR_ErrorToString (errorNumber, PR_LANGUAGE_EN)));
     148                 :          0 :       return;
     149                 :            :     }
     150                 :            : 
     151                 :            :   // PR_ErrorToString does not handle errors outside the range above, so we handle them ourselves.
     152                 :            :   const char *errorText;
     153   [ #  #  #  #  :          0 :   switch (errorNumber) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     154                 :          0 :   default: errorText = "Unknown error"; break;
     155                 :            : #define NSSYERROR(code,msg) case code: errorText = msg; break
     156                 :            : #include "stapsslerr.h"
     157                 :            : #undef NSSYERROR
     158                 :            :     }
     159                 :            : 
     160         [ #  # ]:          0 :   nsscommon_error (_F("(%d) %s", errorNumber, errorText));
     161                 :            : }
     162                 :            : 
     163                 :            : extern "C"
     164                 :            : SECStatus
     165                 :        103 : nssInit (const char *db_path, int readWrite, int issueMessage)
     166                 :            : {
     167                 :            :   SECStatus secStatus;
     168         [ +  + ]:        103 :   if (readWrite)
     169                 :          9 :     secStatus = NSS_InitReadWrite (db_path);
     170                 :            :   else
     171                 :         94 :     secStatus = NSS_Init (db_path);
     172 [ +  + ][ -  + ]:        103 :   if (secStatus != SECSuccess && issueMessage)
     173                 :            :     {
     174         [ #  # ]:          0 :       nsscommon_error (_F("Error initializing NSS for %s", db_path));
     175                 :          0 :       nssError ();
     176                 :            :     }
     177                 :        103 :   return secStatus;
     178                 :            : }
     179                 :            : 
     180                 :            : extern "C"
     181                 :            : void
     182                 :        102 : nssCleanup (const char *db_path)
     183                 :            : {
     184                 :            :   // Make sure that NSS has been initialized. Some early versions of NSS do not check this
     185                 :            :   // within NSS_Shutdown().
     186                 :            :   // When called with no certificate database path (db_path == 0), then the caller does
     187                 :            :   // not know whether NSS has actually been initialized. For example, the rpm finder,
     188                 :            :   // which calls here to shutdown NSS manually if rpmFreeCrypto() is not available
     189                 :            :   // (see rpm_finder.cxx:missing_rpm_enlist).
     190                 :            :   // However, if we're trying to close a certificate database which has not been initialized,
     191                 :            :   // then we have a (non fatal) internal error.
     192         [ -  + ]:        102 :   if (! NSS_IsInitialized ())
     193                 :            :     {
     194         [ #  # ]:          0 :       if (db_path)
     195                 :            :         {
     196         [ #  # ]:          0 :           nsscommon_error (_F("WARNING: Attempt to shutdown NSS for database %s, which was never initialized", db_path));
     197                 :            :         }
     198                 :        102 :       return;
     199                 :            :     }
     200                 :            : 
     201                 :            :   // Shutdown NSS and ensure that it went down successfully. This is because we can not
     202                 :            :   // initialize NSS again if it does not.
     203         [ -  + ]:        102 :   if (NSS_Shutdown () != SECSuccess)
     204                 :            :     {
     205         [ #  # ]:          0 :       if (db_path)
     206         [ #  # ]:          0 :         nsscommon_error (_F("Unable to shutdown NSS for database %s", db_path));
     207                 :            :       else
     208                 :          0 :         nsscommon_error (_("Unable to shutdown NSS"));
     209                 :          0 :       nssError ();
     210                 :            :     }
     211                 :            : }
     212                 :            : 
     213                 :            : // Certificate database password support functions.
     214                 :            : //
     215                 :            : // Disable character echoing, if the fd is a tty.
     216                 :            : static void
     217                 :          0 : echoOff(int fd)
     218                 :            : {
     219         [ #  # ]:          0 :   if (isatty(fd)) {
     220                 :            :     struct termios tio;
     221                 :          0 :     tcgetattr(fd, &tio);
     222                 :          0 :     tio.c_lflag &= ~ECHO;
     223                 :          0 :     tcsetattr(fd, TCSAFLUSH, &tio);
     224                 :            :   }
     225                 :          0 : }
     226                 :            : 
     227                 :            : /* Enable character echoing, if the fd is a tty.  */
     228                 :            : static void
     229                 :          0 : echoOn(int fd)
     230                 :            : {
     231         [ #  # ]:          0 :   if (isatty(fd)) {
     232                 :            :     struct termios tio;
     233                 :          0 :     tcgetattr(fd, &tio);
     234                 :          0 :     tio.c_lflag |= ECHO;
     235                 :          0 :     tcsetattr(fd, TCSAFLUSH, &tio);
     236                 :            :   }
     237                 :          0 : }
     238                 :            : 
     239                 :            : /*
     240                 :            :  * This function is our custom password handler that is called by
     241                 :            :  * NSS when retrieving private certs and keys from the database. Returns a
     242                 :            :  * pointer to a string with a password for the database. Password pointer
     243                 :            :  * must be allocated by one of the NSPR memory allocation functions, or by PORT_Strdup,
     244                 :            :  * and will be freed by the caller.
     245                 :            :  */
     246                 :            : extern "C"
     247                 :            : char *
     248                 :          0 : nssPasswordCallback (PK11SlotInfo *info __attribute ((unused)), PRBool retry, void *arg)
     249                 :            : {
     250                 :            :   static int retries = 0;
     251                 :            :   #define PW_MAX 200
     252                 :          0 :   char* password = NULL;
     253                 :          0 :   char* password_ret = NULL;
     254                 :            :   const char *dbname ;
     255                 :            :   int infd;
     256                 :            :   int isTTY;
     257                 :            : 
     258         [ #  # ]:          0 :   if (! retry)
     259                 :            :     {
     260                 :            :       /* Not a retry. */
     261                 :          0 :       retries = 0;
     262                 :            :     }
     263                 :            :   else
     264                 :            :     {
     265                 :            :       /* Maximum of 2 retries for bad password.  */
     266         [ #  # ]:          0 :       if (++retries > 2)
     267                 :          0 :         return NULL; /* No more retries */
     268                 :            :     }
     269                 :            : 
     270                 :            :   /* Can only prompt for a password if stdin is a tty.  */
     271                 :          0 :   infd = fileno (stdin);
     272                 :          0 :   isTTY = isatty (infd);
     273         [ #  # ]:          0 :   if (! isTTY)
     274                 :            :     {
     275                 :          0 :       nsscommon_error (_("Cannot prompt for certificate database password. stdin is not a tty"));
     276                 :          0 :       return NULL;
     277                 :            :     }
     278                 :            : 
     279                 :            :   /* Prompt for password */
     280                 :          0 :   password = (char *)PORT_Alloc (PW_MAX);
     281         [ #  # ]:          0 :   if (! password)
     282                 :            :     {
     283                 :          0 :       nssError ();
     284                 :          0 :       return NULL;
     285                 :            :     }
     286                 :            : 
     287                 :          0 :   dbname = (const char *)arg;
     288 [ #  # ][ #  # ]:          0 :   cerr << _F("Password for certificate database in %s: ", dbname) << flush;
     289                 :          0 :   echoOff (infd);
     290                 :          0 :   password_ret = fgets (password, PW_MAX, stdin);
     291                 :          0 :   cerr << endl << flush;
     292                 :          0 :   echoOn(infd);
     293                 :            : 
     294         [ #  # ]:          0 :   if (password_ret)
     295                 :            :     /* stomp on the newline */
     296                 :          0 :     *strchrnul (password, '\n') = '\0';
     297                 :            :   else
     298                 :          0 :     PORT_Free (password);
     299                 :            : 
     300                 :          0 :   return password_ret;
     301                 :            : }
     302                 :            : 
     303                 :            : static int
     304                 :          2 : create_server_cert_db (const char *db_path)
     305                 :            : {
     306                 :          2 :   return create_dir (db_path, 0755);
     307                 :            : }
     308                 :            : 
     309                 :            : static int
     310                 :          1 : create_client_cert_db (const char *db_path)
     311                 :            : {
     312                 :            :   // Same properties as the server's database, at present.
     313                 :          1 :   return create_server_cert_db (db_path);
     314                 :            : }
     315                 :            : 
     316                 :            : static int
     317                 :          2 : clean_cert_db (const string &db_path)
     318                 :            : {
     319                 :            :   // First remove all files from the directory
     320                 :            :   glob_t globbuf;
     321         [ +  - ]:          2 :   string filespec = db_path + "/*";
     322         [ +  - ]:          2 :   int r = glob (filespec.c_str (), 0, NULL, & globbuf);
     323 [ +  - ][ -  + ]:          2 :   if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
     324 [ #  # ][ #  # ]:          0 :     nsscommon_error (_F("Could not search certificate database directory %s", db_path.c_str ()));
         [ #  # ][ #  # ]
     325         [ -  + ]:          2 :   else if (r != GLOB_NOMATCH)
     326                 :            :     {
     327         [ #  # ]:          0 :       for (unsigned i = 0; i < globbuf.gl_pathc; ++i)
     328                 :            :         {
     329 [ #  # ][ #  # ]:          0 :           if (remove_file_or_dir (globbuf.gl_pathv[i]) != 0)
     330 [ #  # ][ #  # ]:          0 :             nsscommon_error (_F("Could not remove %s", globbuf.gl_pathv[i]));
                 [ #  # ]
     331                 :            :         }
     332                 :            :     }
     333                 :            : 
     334                 :            :   // Now remove the directory itself.
     335 [ +  - ][ +  - ]:          2 :   if (remove_file_or_dir (db_path.c_str ()) != 0)
                 [ -  + ]
     336                 :            :     {
     337                 :          0 :       nsscommon_error (_F("Could not remove certificate database directory %s\n%s",
     338   [ #  #  #  # ]:          0 :                           db_path.c_str (), strerror (errno)));
         [ #  # ][ #  # ]
     339                 :          0 :       return 1;
     340                 :            :     }
     341                 :            : 
     342         [ +  - ]:          2 :   return 0;
     343                 :            : }
     344                 :            : 
     345                 :            : static int
     346                 :          1 : init_password (PK11SlotInfo *slot, const string &db_path, bool use_password)
     347                 :            : {
     348                 :            :   // Prompt for the database password, if we're using one. Keep the passwords in memory for as
     349                 :            :   // little time as possible.
     350                 :            :   SECStatus secStatus;
     351         [ -  + ]:          1 :   if (use_password)
     352                 :            :     {
     353                 :          0 :       char *pw1 = 0;
     354                 :            :       int attempts;
     355                 :          0 :       const int max_attempts = 3;
     356         [ #  # ]:          0 :       for (attempts = 0; attempts < max_attempts; ++attempts)
     357                 :            :         {
     358                 :          0 :           pw1 = nssPasswordCallback (slot, false, (void*)db_path.c_str ());
     359         [ #  # ]:          0 :           if (! pw1)
     360                 :          0 :             continue;
     361                 :          0 :           cerr << "Confirm ";
     362                 :          0 :           bool match = false;
     363                 :          0 :           char *pw2 = nssPasswordCallback (slot, false, (void*)db_path.c_str ());
     364         [ #  # ]:          0 :           if (pw2)
     365                 :            :             {
     366         [ #  # ]:          0 :               if (strcmp (pw1, pw2) == 0)
     367                 :          0 :                 match = true;
     368                 :            :               else
     369                 :          0 :                 nsscommon_error (_("Passwords do not match"));
     370                 :          0 :               memset (pw2, 0, strlen (pw2));
     371                 :          0 :               PORT_Free (pw2);
     372                 :            :             }
     373         [ #  # ]:          0 :           if (match)
     374                 :          0 :             break;
     375                 :          0 :           memset (pw1, 0, strlen (pw1));
     376                 :          0 :           PORT_Free (pw1);
     377                 :            :         }
     378         [ #  # ]:          0 :       if (attempts >= max_attempts)
     379                 :            :         {
     380                 :          0 :           nsscommon_error (_("Too many password attempts"));
     381                 :          0 :           return 1;
     382                 :            :         }
     383                 :          0 :       secStatus = PK11_InitPin (slot, 0, pw1);
     384                 :          0 :       memset (pw1, 0, strlen (pw1));
     385                 :          0 :       PORT_Free (pw1);
     386                 :            :     }
     387                 :            :   else
     388                 :          1 :     secStatus = PK11_InitPin (slot, 0, 0);
     389                 :            : 
     390         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     391                 :            :     {
     392         [ #  # ]:          0 :       nsscommon_error (_F("Could not initialize pin for certificate database %s", db_path.c_str()));
     393                 :          0 :       nssError ();
     394                 :          0 :       return 1;
     395                 :            :     }
     396                 :            : 
     397                 :          1 :   return 0;
     398                 :            : }
     399                 :            : 
     400                 :            : static SECKEYPrivateKey *
     401                 :          1 : generate_private_key (const string &db_path, PK11SlotInfo *slot, SECKEYPublicKey **pubkeyp)
     402                 :            : {
     403 [ +  - ][ -  + ]:          1 :   if (PK11_Authenticate (slot, PR_TRUE, 0) != SECSuccess)
     404                 :            :     {
     405                 :          0 :       nsscommon_error (_F("Unable to authenticate the default slot for certificate database %s",
     406 [ #  # ][ #  # ]:          0 :                           db_path.c_str ()));
         [ #  # ][ #  # ]
     407         [ #  # ]:          0 :       nssError ();
     408                 :          0 :       return 0;
     409                 :            :     }
     410                 :            : 
     411                 :            :   // Do some random-number initialization.
     412                 :            :   // TODO: We can do better.
     413                 :          1 :   srand (time (NULL));
     414                 :            :   char randbuf[64];
     415         [ +  + ]:         65 :   for (unsigned i = 0; i < sizeof (randbuf); ++i)
     416                 :         64 :     randbuf[i] = rand ();
     417         [ +  - ]:          1 :   PK11_RandomUpdate (randbuf, sizeof (randbuf));
     418                 :          1 :   memset (randbuf, 0, sizeof (randbuf));
     419                 :            : 
     420                 :            :   // Set up for RSA.
     421                 :            :   PK11RSAGenParams rsaparams;
     422                 :          1 :   rsaparams.keySizeInBits = 1024;
     423                 :          1 :   rsaparams.pe = 0x010001;
     424                 :          1 :   CK_MECHANISM_TYPE mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
     425                 :            : 
     426                 :            :   // Generate the key pair.
     427                 :            :   SECKEYPrivateKey *privKey = PK11_GenerateKeyPair (slot, mechanism, & rsaparams, pubkeyp,
     428                 :            :                                                     PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/,
     429         [ +  - ]:          1 :                                                     0/*pwdata*/);
     430         [ -  + ]:          1 :   if (! privKey)
     431                 :            :     {
     432         [ #  # ]:          0 :       nsscommon_error (_("Unable to generate public/private key pair"));
     433         [ #  # ]:          0 :       nssError ();
     434                 :            :     }
     435                 :          1 :   return privKey;
     436                 :            : }
     437                 :            : 
     438                 :            : static CERTCertificateRequest *
     439                 :          1 : generate_cert_request (SECKEYPublicKey *pubk, CERTName *subject)
     440                 :            : {
     441                 :          1 :   CERTSubjectPublicKeyInfo *spki = SECKEY_CreateSubjectPublicKeyInfo (pubk);
     442         [ -  + ]:          1 :   if (! spki)
     443                 :            :     {
     444                 :          0 :       nsscommon_error (_("Unable to create subject public key info for certificate request"));
     445                 :          0 :       nssError ();
     446                 :          0 :       return 0;
     447                 :            :     }
     448                 :            :   
     449                 :            :   /* Generate certificate request */
     450                 :          1 :   CERTCertificateRequest *cr = CERT_CreateCertificateRequest (subject, spki, 0);
     451                 :          1 :   SECKEY_DestroySubjectPublicKeyInfo (spki);
     452         [ -  + ]:          1 :   if (! cr)
     453                 :            :     {
     454                 :          0 :       nsscommon_error (_("Unable to create certificate request"));
     455                 :          0 :       nssError ();
     456                 :            :     }
     457                 :          1 :   return cr;
     458                 :            : }
     459                 :            : 
     460                 :            : static CERTCertificate *
     461                 :          1 : create_cert (CERTCertificateRequest *certReq, const string &dnsNames)
     462                 :            : {
     463                 :            :   // What is the current date and time?
     464         [ +  - ]:          1 :   PRTime now = PR_Now ();
     465                 :            : 
     466                 :            :   // What is the date and time 1 year from now?
     467                 :            :   PRExplodedTime printableTime;
     468         [ +  - ]:          1 :   PR_ExplodeTime (now, PR_GMTParameters, & printableTime);
     469                 :          1 :   printableTime.tm_month += 12;
     470         [ +  - ]:          1 :   PRTime after = PR_ImplodeTime (& printableTime);
     471                 :            :  
     472                 :            :   // Note that the time is now in micro-second units.
     473         [ +  - ]:          1 :   CERTValidity *validity = CERT_CreateValidity (now, after);
     474         [ -  + ]:          1 :   if (! validity)
     475                 :            :     {
     476         [ #  # ]:          0 :       nsscommon_error (_("Unable to create certificate validity dates"));
     477         [ #  # ]:          0 :       nssError ();
     478                 :          0 :       return 0;
     479                 :            :     }
     480                 :            : 
     481                 :            :   // Create a default serial number using the current time.
     482                 :          1 :   PRTime serialNumber = now >> 19; // copied from certutil.
     483                 :            : 
     484                 :            :   // Create the certificate.
     485                 :            :   CERTCertificate *cert = CERT_CreateCertificate (serialNumber, & certReq->subject, validity,
     486         [ +  - ]:          1 :                                                   certReq);
     487         [ +  - ]:          1 :   CERT_DestroyValidity (validity);
     488         [ -  + ]:          1 :   if (! cert)
     489                 :            :     {
     490         [ #  # ]:          0 :       nsscommon_error (_("Unable to create certificate"));
     491         [ #  # ]:          0 :       nssError ();
     492                 :          0 :       return 0;
     493                 :            :     }
     494                 :            : 
     495                 :            :   // Predeclare these to keep C++ happy about jumps to the label 'error'.
     496                 :          1 :   SECStatus secStatus = SECSuccess;
     497                 :          1 :   unsigned char keyUsage = 0x0;
     498                 :          1 :   PRArenaPool *arena = 0;
     499                 :            : 
     500                 :            :   // Add the extensions that we need.
     501         [ +  - ]:          1 :   void *extHandle = CERT_StartCertExtensions (cert);
     502         [ -  + ]:          1 :   if (! extHandle)
     503                 :            :     {
     504         [ #  # ]:          0 :       nsscommon_error (_("Unable to allocate certificate extensions"));
     505         [ #  # ]:          0 :       nssError ();
     506                 :          0 :       goto error;
     507                 :            :     }
     508                 :            : 
     509                 :            :   // Cert type extension.
     510                 :          1 :   keyUsage |= (0x80 >> 1); // SSL Server
     511                 :          1 :   keyUsage |= (0x80 >> 3); // Object signer
     512                 :          1 :   keyUsage |= (0x80 >> 7); // Object signing CA
     513                 :            : 
     514                 :            :   SECItem bitStringValue;
     515                 :          1 :   bitStringValue.data = & keyUsage;
     516                 :          1 :   bitStringValue.len = 1;
     517                 :            : 
     518                 :            :   secStatus = CERT_EncodeAndAddBitStrExtension (extHandle,
     519                 :            :                                                 SEC_OID_NS_CERT_EXT_CERT_TYPE,
     520         [ +  - ]:          1 :                                                 & bitStringValue, PR_TRUE);
     521         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     522                 :            :     {
     523         [ #  # ]:          0 :       nsscommon_error (_("Unable to encode certificate type extensions"));
     524         [ #  # ]:          0 :       nssError ();
     525                 :          0 :       goto error;
     526                 :            :     }
     527                 :            : 
     528                 :            :   // Alternate dns name extension.
     529 [ +  - ][ +  - ]:          1 :   if (! dnsNames.empty ())
     530                 :            :     {
     531         [ +  - ]:          1 :       arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
     532         [ -  + ]:          1 :       if (! arena)
     533                 :            :         {
     534         [ #  # ]:          0 :           nsscommon_error (_("Unable to allocate alternate DNS name extension for certificate"));
     535                 :            :           goto error;
     536                 :            :         }
     537                 :            : 
     538                 :            :       // Walk down the comma separated list of names.
     539                 :          1 :       CERTGeneralName *nameList = 0;
     540                 :          1 :       CERTGeneralName *current = 0;
     541                 :          1 :       PRCList *prev = 0;
     542         [ +  - ]:          1 :       vector<string>components;
     543 [ +  - ][ +  - ]:          1 :       tokenize (dnsNames, components, ",");
                 [ +  - ]
     544         [ +  + ]:          2 :       for (unsigned i = 0; i < components.size (); ++i)
     545                 :            :         {
     546 [ +  - ][ +  - ]:          1 :           char *tbuf = (char *)PORT_ArenaAlloc (arena, components[i].size () + 1);
     547         [ +  - ]:          1 :           strcpy (tbuf, components[i].c_str ());
     548                 :            : 
     549         [ +  - ]:          1 :           current = (CERTGeneralName *)PORT_ZAlloc (sizeof (CERTGeneralName));
     550         [ -  + ]:          1 :           if (! current)
     551                 :            :             {
     552         [ #  # ]:          0 :               nsscommon_error (_("Unable to allocate alternate DNS name extension for certificate"));
     553                 :            :               goto error;
     554                 :            :             }
     555         [ -  + ]:          1 :           if (prev)
     556                 :            :             {
     557                 :          0 :               current->l.prev = prev;
     558                 :          0 :               prev->next = & current->l;
     559                 :            :             }
     560                 :            :           else
     561                 :          1 :             nameList = current;
     562                 :            : 
     563                 :          1 :           current->type = certDNSName;
     564                 :          1 :           current->name.other.data = (unsigned char *)tbuf;
     565                 :          1 :           current->name.other.len = strlen (tbuf);
     566                 :          1 :           prev = & current->l;
     567                 :            :         }
     568                 :            : 
     569                 :            :       // At this point nameList points to the head of a doubly linked,
     570                 :            :       // but not yet circular, list and current points to its tail.
     571         [ +  - ]:          1 :       if (nameList)
     572                 :            :         {
     573                 :            :           // Make nameList circular.
     574                 :          1 :           nameList->l.prev = prev;
     575                 :          1 :           current->l.next = & nameList->l;
     576                 :            : 
     577                 :            :           // Encode and add the extension.
     578                 :            :           SECItem item;
     579         [ +  - ]:          1 :           secStatus = CERT_EncodeAltNameExtension (arena, nameList, & item);
     580         [ -  + ]:          1 :           if (secStatus != SECSuccess)
     581                 :            :             {
     582         [ #  # ]:          0 :               nsscommon_error (_("Unable to encode alternate DNS name extension for certificate"));
     583         [ #  # ]:          0 :               nssError ();
     584                 :            :               goto error;
     585                 :            :             }
     586                 :            :           secStatus = CERT_AddExtension(extHandle,
     587                 :            :                                         SEC_OID_X509_SUBJECT_ALT_NAME,
     588         [ +  - ]:          1 :                                         & item, PR_FALSE, PR_TRUE);
     589         [ -  + ]:          1 :           if (secStatus != SECSuccess)
     590                 :            :             {
     591         [ #  # ]:          0 :               nsscommon_error (_("Unable to add alternate DNS name extension for certificate"));
     592         [ #  # ]:          1 :               nssError ();
     593                 :            :               goto error;
     594                 :            :             }
     595 [ +  - ][ +  - ]:          1 :         }
     596                 :            :     } // extra dns names specified.
     597                 :            : 
     598                 :            :   // We did not create any extensions on the cert request.
     599         [ -  + ]:          1 :   assert (certReq->attributes != NULL);
     600         [ -  + ]:          1 :   assert (certReq->attributes[0] == NULL);
     601                 :            : 
     602                 :            :   // Finished with cert extensions.
     603         [ +  - ]:          1 :   secStatus = CERT_FinishExtensions (extHandle);
     604         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     605                 :            :     {
     606         [ #  # ]:          0 :       nsscommon_error (_("Unable to complete alternate DNS name extension for certificate"));
     607         [ #  # ]:          0 :       nssError ();
     608                 :          0 :       goto error;
     609                 :            :     }
     610                 :            : 
     611                 :          1 :   return cert;
     612                 :            : 
     613                 :            :  error:
     614         [ #  # ]:          0 :   if (arena)
     615         [ #  # ]:          0 :     PORT_FreeArena (arena, PR_FALSE);
     616         [ #  # ]:          0 :   CERT_DestroyCertificate (cert);
     617                 :          1 :   return 0;
     618                 :            : }
     619                 :            : 
     620                 :            : static SECItem *
     621                 :          1 : sign_cert (CERTCertificate *cert, SECKEYPrivateKey *privKey)
     622                 :            : {
     623                 :            :   SECOidTag algID = SEC_GetSignatureAlgorithmOidTag (privKey->keyType,
     624         [ +  - ]:          1 :                                                      SEC_OID_UNKNOWN);
     625         [ -  + ]:          1 :   if (algID == SEC_OID_UNKNOWN)
     626                 :            :     {
     627         [ #  # ]:          0 :       nsscommon_error (_("Unable to determine the signature algorithm for the signing the certificate"));
     628         [ #  # ]:          0 :       nssError ();
     629                 :          0 :       return 0;
     630                 :            :     }
     631                 :            : 
     632                 :          1 :   PRArenaPool *arena = cert->arena;
     633         [ +  - ]:          1 :   SECStatus rv = SECOID_SetAlgorithmID (arena, & cert->signature, algID, 0);
     634         [ -  + ]:          1 :   if (rv != SECSuccess)
     635                 :            :     {
     636         [ #  # ]:          0 :       nsscommon_error (_("Unable to set the signature algorithm for signing the certificate"));
     637         [ #  # ]:          0 :       nssError ();
     638                 :          0 :       return 0;
     639                 :            :     }
     640                 :            : 
     641                 :            :   /* we only deal with cert v3 here */
     642                 :          1 :   *(cert->version.data) = 2;
     643                 :          1 :   cert->version.len = 1;
     644                 :            : 
     645                 :            :   SECItem der;
     646                 :          1 :   der.len = 0;
     647                 :          1 :   der.data = 0;
     648                 :            :   void *dummy = SEC_ASN1EncodeItem (arena, & der, cert,
     649         [ +  - ]:          1 :                                     SEC_ASN1_GET (CERT_CertificateTemplate));
     650         [ -  + ]:          1 :   if (! dummy)
     651                 :            :     {
     652         [ #  # ]:          0 :       nsscommon_error (_("Unable to encode the certificate for signing"));
     653         [ #  # ]:          0 :       nssError ();
     654                 :          0 :       return 0;
     655                 :            :     }
     656                 :            : 
     657         [ +  - ]:          1 :   SECItem *result = (SECItem *)PORT_ArenaZAlloc (arena, sizeof (SECItem));
     658         [ -  + ]:          1 :   if (! result)
     659                 :            :     {
     660         [ #  # ]:          0 :       nsscommon_error (_("Unable to allocate memory for signing the certificate"));
     661                 :          0 :       return 0;
     662                 :            :     }
     663                 :            : 
     664         [ +  - ]:          1 :   rv = SEC_DerSignData (arena, result, der.data, der.len, privKey, algID);
     665         [ -  + ]:          1 :   if (rv != SECSuccess)
     666                 :            :     {
     667         [ #  # ]:          0 :       nsscommon_error (_("Unable to sign the certificate"));
     668         [ #  # ]:          0 :       nssError ();
     669                 :          0 :       return 0;
     670                 :            :     }
     671                 :            : 
     672                 :          1 :   cert->derCert = *result;
     673                 :          1 :   return result;
     674                 :            : }
     675                 :            : 
     676                 :            : static SECStatus
     677                 :          1 : add_server_cert (const string &db_path, SECItem *certDER, PK11SlotInfo *slot)
     678                 :            : {
     679                 :            :   // Decode the cert.
     680                 :          1 :   CERTCertificate *cert = CERT_DecodeCertFromPackage((char *)certDER->data, certDER->len);
     681         [ -  + ]:          1 :   if (! cert)
     682                 :            :     {
     683                 :          0 :       nsscommon_error (_("Unable to decode certificate"));
     684                 :          0 :       nssError ();
     685                 :          0 :       return SECFailure;
     686                 :            :     }
     687                 :            : 
     688                 :            :   // Import it into the database.
     689                 :          1 :   CERTCertDBHandle *handle = 0;
     690                 :          1 :   CERTCertTrust *trust = NULL;
     691                 :            :   SECStatus secStatus = PK11_ImportCert (slot, cert, CK_INVALID_HANDLE,
     692                 :          1 :                                          server_cert_nickname (), PR_FALSE);
     693         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     694                 :            :     {
     695         [ #  # ]:          0 :       nsscommon_error (_F("Unable to import certificate into the database at %s", db_path.c_str ()));
     696                 :          0 :       nssError ();
     697                 :          0 :       goto done;
     698                 :            :     }
     699                 :            :   
     700                 :            :   // Make it a trusted server and signer.
     701                 :          1 :   trust = (CERTCertTrust *)PORT_ZAlloc (sizeof (CERTCertTrust));
     702         [ -  + ]:          1 :   if (! trust)
     703                 :            :     {
     704                 :          0 :       nsscommon_error (_("Unable to allocate certificate trust"));
     705                 :          0 :       secStatus = SECFailure;
     706                 :          0 :       goto done;
     707                 :            :     }
     708                 :            : 
     709                 :          1 :   secStatus = CERT_DecodeTrustString (trust, "PCu,,PCu");
     710         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     711                 :            :     {
     712                 :          0 :       nsscommon_error (_("Unable decode trust string 'PCu,,PCu'"));
     713                 :          0 :       nssError ();
     714                 :          0 :       goto done;
     715                 :            :     }
     716                 :            :     
     717                 :          1 :   handle = CERT_GetDefaultCertDB ();
     718         [ -  + ]:          1 :   assert (handle);
     719                 :          1 :   secStatus = CERT_ChangeCertTrust (handle, cert, trust);
     720         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     721                 :            :     {
     722                 :          0 :       nsscommon_error (_("Unable to change certificate trust"));
     723                 :          0 :       nssError ();
     724                 :            :     }
     725                 :            : 
     726                 :            : done:
     727                 :          1 :   CERT_DestroyCertificate (cert);
     728         [ +  - ]:          1 :   if (trust)
     729                 :          1 :     PORT_Free (trust);
     730                 :          1 :   return secStatus;
     731                 :            : }
     732                 :            : 
     733                 :            : SECStatus
     734                 :          5 : add_client_cert (const string &inFileName, const string &db_path)
     735                 :            : {
     736 [ +  - ][ +  - ]:          5 :   FILE *inFile = fopen (inFileName.c_str (), "rb");
     737         [ -  + ]:          5 :   if (! inFile)
     738                 :            :     {
     739                 :          0 :       nsscommon_error (_F("Could not open certificate file %s for reading\n%s",
     740   [ #  #  #  # ]:          0 :                           inFileName.c_str (), strerror (errno)));
         [ #  # ][ #  # ]
     741                 :          0 :       return SECFailure;
     742                 :            :     }
     743                 :            : 
     744                 :          5 :   int fd = fileno (inFile);
     745                 :            :   struct stat info;
     746                 :          5 :   int rc = fstat (fd, &info);
     747         [ -  + ]:          5 :   if (rc != 0)
     748                 :            :     {
     749                 :          0 :       nsscommon_error (_F("Could not obtain information about certificate file %s\n%s",
     750   [ #  #  #  # ]:          0 :                           inFileName.c_str (), strerror (errno)));
         [ #  # ][ #  # ]
     751         [ #  # ]:          0 :       fclose (inFile);
     752                 :          0 :       return SECFailure;
     753                 :            :     }
     754                 :            : 
     755                 :            :   SECItem certDER;
     756                 :          5 :   certDER.len = info.st_size;
     757         [ +  - ]:          5 :   certDER.data = (unsigned char *)PORT_Alloc (certDER.len);
     758         [ -  + ]:          5 :   if (certDER.data == NULL)
     759                 :            :     {
     760                 :          0 :       nsscommon_error (_F("Could not allocate certDER\n%s",
     761 [ #  # ][ #  # ]:          0 :                           strerror (errno)));
                 [ #  # ]
     762         [ #  # ]:          0 :       fclose (inFile);
     763                 :          0 :       return SECFailure;
     764                 :            :     }
     765         [ +  - ]:          5 :   size_t read = fread (certDER.data, 1, certDER.len, inFile);
     766         [ +  - ]:          5 :   fclose (inFile);
     767         [ -  + ]:          5 :   if (read != certDER.len)
     768                 :            :     {
     769                 :          0 :       nsscommon_error (_F("Error reading from certificate file %s\n%s",
     770   [ #  #  #  # ]:          0 :                           inFileName.c_str (), strerror (errno)));
         [ #  # ][ #  # ]
     771                 :          0 :       return SECFailure;
     772                 :            :     }
     773                 :            : 
     774                 :            :   // See if the database already exists and can be initialized.
     775 [ +  - ][ +  - ]:          5 :   SECStatus secStatus = nssInit (db_path.c_str (), 1/*readwrite*/, 0/*issueMessage*/);
     776         [ +  + ]:          5 :   if (secStatus != SECSuccess)
     777                 :            :     {
     778                 :            :       // Try again with a fresh database.
     779 [ +  - ][ +  - ]:          1 :       if (clean_cert_db (db_path.c_str ()) != 0)
         [ +  - ][ +  - ]
                 [ -  + ]
     780                 :            :         {
     781                 :            :           // Message already issued.
     782                 :          0 :           return SECFailure;
     783                 :            :         }
     784                 :            : 
     785                 :            :       // Make sure the given path exists.
     786 [ +  - ][ +  - ]:          1 :       if (create_client_cert_db (db_path.c_str ()) != 0)
                 [ -  + ]
     787                 :            :         {
     788                 :          0 :           nsscommon_error (_F("Could not create certificate database directory %s",
     789 [ #  # ][ #  # ]:          0 :                               db_path.c_str ()));
         [ #  # ][ #  # ]
     790                 :          0 :           return SECFailure;
     791                 :            :         }
     792                 :            : 
     793                 :            :       // Initialize the new database.
     794 [ +  - ][ +  - ]:          1 :       secStatus = nssInit (db_path.c_str (), 1/*readwrite*/);
     795         [ -  + ]:          1 :       if (secStatus != SECSuccess)
     796                 :            :         {
     797                 :            :           // Message already issued.
     798                 :          0 :           return SECFailure;
     799                 :            :         }
     800                 :            :     }
     801                 :            : 
     802                 :            :   // Predeclare these to keep C++ happy about jumps to the label 'done'.
     803                 :          5 :   CERTCertificate *cert = 0;
     804                 :          5 :   CERTCertDBHandle *handle = 0;
     805                 :          5 :   CERTCertTrust *trust = 0;
     806                 :          5 :   PK11SlotInfo *slot = 0;
     807                 :            : 
     808                 :            :   // Add the cert to the database
     809                 :            :   // Decode the cert.
     810                 :          5 :   secStatus = SECFailure;
     811         [ +  - ]:          5 :   cert = CERT_DecodeCertFromPackage ((char *)certDER.data, certDER.len);
     812         [ -  + ]:          5 :   if (! cert)
     813                 :            :     {
     814         [ #  # ]:          0 :       nsscommon_error (_("Unable to decode certificate"));
     815         [ #  # ]:          0 :       nssError ();
     816                 :          0 :       goto done;
     817                 :            :     }
     818                 :            : 
     819                 :            :   // We need the internal slot for this database.
     820         [ +  - ]:          5 :   slot = PK11_GetInternalKeySlot ();
     821         [ -  + ]:          5 :   if (! slot)
     822                 :            :     {
     823 [ #  # ][ #  # ]:          0 :       nsscommon_error (_F("Could not obtain internal key slot for certificate database %s", db_path.c_str()));
         [ #  # ][ #  # ]
     824         [ #  # ]:          0 :       nssError ();
     825                 :          0 :       goto done;
     826                 :            :     }
     827                 :            : 
     828                 :            :   // Import it into the database.
     829                 :            :   secStatus = PK11_ImportCert (slot, cert, CK_INVALID_HANDLE,
     830         [ +  - ]:          5 :                                server_cert_nickname (), PR_FALSE);
     831         [ -  + ]:          5 :   if (secStatus != SECSuccess)
     832                 :            :     {
     833 [ #  # ][ #  # ]:          0 :       nsscommon_error (_F("Could not import certificate into the database at %s", db_path.c_str()));
         [ #  # ][ #  # ]
     834         [ #  # ]:          0 :       nssError ();
     835                 :          0 :       goto done;
     836                 :            :     }
     837                 :            :   
     838                 :            :   // Make it a trusted SSL peer.
     839         [ +  - ]:          5 :   trust = (CERTCertTrust *)PORT_ZAlloc (sizeof (CERTCertTrust));
     840         [ -  + ]:          5 :   if (! trust)
     841                 :            :     {
     842         [ #  # ]:          0 :       nsscommon_error (_("Could not allocate certificate trust"));
     843                 :          0 :       goto done;
     844                 :            :     }
     845                 :            : 
     846         [ +  - ]:          5 :   secStatus = CERT_DecodeTrustString (trust, "P,P,P");
     847         [ -  + ]:          5 :   if (secStatus != SECSuccess)
     848                 :            :     {
     849         [ #  # ]:          0 :       nsscommon_error (_("Unable decode trust string 'P,P,P'"));
     850         [ #  # ]:          0 :       nssError ();
     851                 :          0 :       goto done;
     852                 :            :     }
     853                 :            : 
     854         [ +  - ]:          5 :   handle = CERT_GetDefaultCertDB ();
     855         [ -  + ]:          5 :   assert (handle);
     856         [ +  - ]:          5 :   secStatus = CERT_ChangeCertTrust (handle, cert, trust);
     857         [ -  + ]:          5 :   if (secStatus != SECSuccess)
     858                 :            :     {
     859         [ #  # ]:          0 :       nsscommon_error (_("Unable to change certificate trust"));
     860         [ #  # ]:          0 :       nssError ();
     861                 :            :     }
     862                 :            : 
     863                 :            :  done:
     864                 :            :   // Free NSS/NSPR objects and shutdown NSS.
     865         [ +  - ]:          5 :   if (slot)
     866         [ +  - ]:          5 :     PK11_FreeSlot (slot);
     867         [ +  - ]:          5 :   if (trust)
     868         [ +  - ]:          5 :     PORT_Free (trust);
     869         [ +  - ]:          5 :   if (cert)
     870         [ +  - ]:          5 :     CERT_DestroyCertificate (cert);
     871         [ +  - ]:          5 :   if (certDER.data)
     872         [ +  - ]:          5 :     PORT_Free (certDER.data);
     873 [ +  - ][ +  - ]:          5 :   nssCleanup (db_path.c_str ());
     874                 :            : 
     875                 :            :   // Make sure that the cert database files are read/write by the owner and
     876                 :            :   // readable by all.
     877                 :            :   glob_t globbuf;
     878         [ +  - ]:          5 :   string filespec = db_path + "/*";
     879         [ +  - ]:          5 :   int r = glob (filespec.c_str (), 0, NULL, & globbuf);
     880 [ +  - ][ -  + ]:          5 :   if (r == GLOB_NOSPACE || r == GLOB_ABORTED) {
     881                 :            :     // Not fatal, just a warning
     882 [ #  # ][ #  # ]:          0 :     nsscommon_error (_F("Could not search certificate database directory %s", db_path.c_str ()));
         [ #  # ][ #  # ]
     883                 :            :   }
     884         [ +  - ]:          5 :   else if (r != GLOB_NOMATCH)
     885                 :            :     {
     886                 :          5 :       mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
     887         [ +  + ]:         20 :       for (unsigned i = 0; i < globbuf.gl_pathc; ++i)
     888                 :            :         {
     889                 :            :           // Not fatal, just a warning
     890         [ -  + ]:         15 :           if (chmod (globbuf.gl_pathv[i], mode) != 0)
     891 [ #  # ][ #  # ]:          0 :             nsscommon_error (_F("Could set file permissions for %s", globbuf.gl_pathv[i]));
                 [ #  # ]
     892                 :            :         }
     893                 :            :     }
     894                 :            :   
     895         [ +  - ]:          5 :   return secStatus;
     896                 :            : }
     897                 :            : 
     898                 :            : int
     899                 :          1 : gen_cert_db (const string &db_path, const string &extraDnsNames, bool use_password)
     900                 :            : {
     901                 :            :   // Log the generation of a new database.
     902                 :          1 :   log (_F("Generating a new certificate database directory in %s",
     903 [ +  - ][ +  - ]:          1 :           db_path.c_str ()));
         [ +  - ][ +  - ]
     904                 :            : 
     905                 :            :   // Start with a clean cert database.
     906 [ +  - ][ +  - ]:          1 :   if (clean_cert_db (db_path.c_str ()) != 0)
         [ +  - ][ +  - ]
                 [ -  + ]
     907                 :            :     {
     908                 :            :       // Message already issued.
     909                 :          0 :       return 1;
     910                 :            :     }
     911                 :            : 
     912                 :            :   // Make sure the given path exists.
     913 [ +  - ][ +  - ]:          1 :   if (create_server_cert_db (db_path.c_str ()) != 0)
                 [ -  + ]
     914                 :            :     {
     915                 :          0 :       nsscommon_error (_F("Could not create certificate database directory %s",
     916 [ #  # ][ #  # ]:          0 :                           db_path.c_str ()));
         [ #  # ][ #  # ]
     917                 :          0 :       return 1;
     918                 :            :     }
     919                 :            : 
     920                 :            :   // Initialize the new database.
     921 [ +  - ][ +  - ]:          1 :   SECStatus secStatus = nssInit (db_path.c_str (), 1/*readwrite*/);
     922         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     923                 :            :     {
     924                 :            :       // Message already issued.
     925                 :          0 :       return 1;
     926                 :            :     }
     927                 :            : 
     928                 :            :   // Pre declare these to keep g++ happy about jumps to the label 'error'.
     929                 :          1 :   CERTName *subject = 0;
     930                 :          1 :   SECKEYPublicKey *pubkey = 0;
     931                 :          1 :   SECKEYPrivateKey *privkey = 0;
     932                 :          1 :   CERTCertificateRequest *cr = 0;
     933                 :          1 :   CERTCertificate *cert = 0;
     934                 :          1 :   SECItem *certDER = 0;
     935         [ +  - ]:          1 :   string dnsNames;
     936                 :            :   int rc;
     937         [ +  - ]:          1 :   string outFileName;
     938                 :          1 :   FILE *outFile = 0;
     939                 :            : 
     940                 :            :   // We need the internal slot for this database.
     941         [ +  - ]:          1 :   PK11SlotInfo *slot = PK11_GetInternalKeySlot ();
     942         [ -  + ]:          1 :   if (! slot)
     943                 :            :     {
     944 [ #  # ][ #  # ]:          0 :       nsscommon_error (_F("Could not obtain internal key slot for certificate database %s", db_path.c_str()));
         [ #  # ][ #  # ]
     945         [ #  # ]:          0 :       nssError ();
     946                 :          0 :       goto error;
     947                 :            :     }
     948                 :            : 
     949                 :            :   // Establish the password (if any) for the new database.
     950         [ +  - ]:          1 :   rc = init_password (slot, db_path, use_password);
     951         [ -  + ]:          1 :   if (rc != 0)
     952                 :            :     {
     953                 :            :       // Messages already issued.
     954                 :          0 :       goto error;
     955                 :            :     }
     956                 :            : 
     957                 :            :   // Format the cert subject.
     958         [ +  - ]:          1 :   subject = CERT_AsciiToName ((char *)"CN=Systemtap Compile Server, OU=Systemtap");
     959         [ -  + ]:          1 :   if (! subject)
     960                 :            :     {
     961         [ #  # ]:          0 :       nsscommon_error (_("Unable to encode certificate common header"));
     962         [ #  # ]:          0 :       nssError ();
     963                 :          0 :       goto error;
     964                 :            :     }
     965                 :            : 
     966                 :            :   // Next, generate the private key.
     967         [ +  - ]:          1 :   privkey = generate_private_key (db_path, slot, & pubkey);
     968         [ -  + ]:          1 :   if (! privkey)
     969                 :            :     {
     970                 :            :       // Message already issued.
     971                 :          0 :       goto error;
     972                 :            :     }
     973                 :            : 
     974                 :            :   // Next, generate a cert request.
     975         [ +  - ]:          1 :   cr = generate_cert_request (pubkey, subject);
     976         [ -  + ]:          1 :   if (! cr)
     977                 :            :     {
     978                 :            :       // Message already issued.
     979                 :          0 :       goto error;
     980                 :            :     }
     981                 :            : 
     982                 :            :   // Now, generate the cert. We need our host name and the supplied additional dns names (if any).
     983                 :            :   struct utsname utsname;
     984                 :          1 :   uname (& utsname);
     985         [ +  - ]:          1 :   dnsNames = utsname.nodename;
     986 [ +  - ][ -  + ]:          1 :   if (! extraDnsNames.empty ())
     987 [ #  # ][ #  # ]:          0 :     dnsNames += "," + extraDnsNames;
                 [ #  # ]
     988         [ +  - ]:          1 :   cert = create_cert (cr, dnsNames);
     989         [ +  - ]:          1 :   CERT_DestroyCertificateRequest (cr);
     990         [ -  + ]:          1 :   if (! cert)
     991                 :            :     {
     992                 :            :       // NSS error already issued.
     993         [ #  # ]:          0 :       nsscommon_error (_("Unable to create certificate"));
     994                 :          0 :       goto error;
     995                 :            :     }
     996                 :            : 
     997                 :            :   // Sign the cert.
     998         [ +  - ]:          1 :   certDER = sign_cert (cert, privkey);
     999         [ -  + ]:          1 :   if (! certDER)
    1000                 :            :     {
    1001                 :            :       // Message already issued.
    1002                 :          0 :       goto error;
    1003                 :            :     }
    1004                 :            : 
    1005                 :            :   // Now output it to a file.
    1006 [ +  - ][ +  - ]:          1 :   outFileName = db_path + "/stap.cert";
                 [ +  - ]
    1007 [ +  - ][ +  - ]:          1 :   outFile = fopen (outFileName.c_str (), "wb");
    1008         [ +  - ]:          1 :   if (outFile)
    1009                 :            :     {
    1010         [ +  - ]:          1 :       size_t written = fwrite (certDER->data, 1, certDER->len, outFile);
    1011         [ -  + ]:          1 :       if (written != certDER->len)
    1012                 :            :         {
    1013                 :          0 :           nsscommon_error (_F("Error writing to certificate file %s\n%s",
    1014   [ #  #  #  # ]:          0 :                               outFileName.c_str (), strerror (errno)));
         [ #  # ][ #  # ]
    1015                 :            :         }
    1016         [ +  - ]:          1 :       fclose (outFile);
    1017                 :            :     }
    1018                 :            :   else
    1019                 :            :     {
    1020                 :          0 :       nsscommon_error (_F("Could not open certificate file %s for writing\n%s",
    1021   [ #  #  #  # ]:          0 :                           outFileName.c_str (), strerror (errno)));
         [ #  # ][ #  # ]
    1022                 :            :     }
    1023                 :            : 
    1024                 :            :   // Add the cert to the database
    1025         [ +  - ]:          1 :   secStatus = add_server_cert (db_path, certDER, slot);
    1026         [ +  - ]:          1 :   CERT_DestroyCertificate (cert);
    1027         [ -  + ]:          1 :   if (secStatus != SECSuccess)
    1028                 :            :     {
    1029                 :            :       // NSS error already issued.
    1030 [ #  # ][ #  # ]:          0 :       nsscommon_error (_F("Unable to add certificate to %s", db_path.c_str ()));
         [ #  # ][ #  # ]
    1031                 :          0 :       goto error;
    1032                 :            :     }
    1033                 :            : 
    1034                 :            :   // Done with the certificate database
    1035         [ +  - ]:          1 :   PK11_FreeSlot (slot);
    1036         [ +  - ]:          1 :   CERT_DestroyName (subject);
    1037         [ +  - ]:          1 :   SECKEY_DestroyPublicKey (pubkey);
    1038         [ +  - ]:          1 :   SECKEY_DestroyPrivateKey (privkey);
    1039                 :          1 :   goto done;
    1040                 :            : 
    1041                 :            :  error:
    1042         [ #  # ]:          0 :   if (slot)
    1043         [ #  # ]:          0 :     PK11_FreeSlot (slot);
    1044         [ #  # ]:          0 :   if (subject)
    1045         [ #  # ]:          0 :     CERT_DestroyName (subject);
    1046         [ #  # ]:          0 :   if (pubkey)
    1047         [ #  # ]:          0 :     SECKEY_DestroyPublicKey (pubkey);
    1048         [ #  # ]:          0 :   if (privkey)
    1049         [ #  # ]:          0 :     SECKEY_DestroyPrivateKey (privkey);
    1050         [ #  # ]:          0 :   if (cert)
    1051         [ #  # ]:          0 :     CERT_DestroyCertificate (cert); // Also destroys certDER.
    1052                 :            : 
    1053                 :            :  done:
    1054 [ +  - ][ +  - ]:          1 :   nssCleanup (db_path.c_str ());
    1055 [ +  - ][ +  - ]:          1 :   return secStatus != SECSuccess;
    1056                 :            : }
    1057                 :            : 
    1058                 :         54 : CERTCertList *get_cert_list_from_db (const string &cert_nickname)
    1059                 :            : {
    1060                 :            :   // Search the client-side database of trusted servers.
    1061                 :         54 :   CERTCertDBHandle *handle = CERT_GetDefaultCertDB ();
    1062         [ -  + ]:         54 :   assert (handle);
    1063                 :         54 :   CERTCertificate *db_cert = PK11_FindCertFromNickname (cert_nickname.c_str (), 0);
    1064         [ +  + ]:         54 :   if (! db_cert)
    1065                 :            :     {
    1066                 :            :       // No trusted servers. Not an error. Just an empty list returned.
    1067                 :          3 :       return 0;
    1068                 :            :     }
    1069                 :            : 
    1070                 :            :   // Here, we have one cert with the desired nickname.
    1071                 :            :   // Now, we will attempt to get a list of ALL certs 
    1072                 :            :   // with the same subject name as the cert we have.  That list 
    1073                 :            :   // should contain, at a minimum, the one cert we have already found.
    1074                 :            :   // If the list of certs is empty (0), the libraries have failed.
    1075                 :            :   CERTCertList *certs = CERT_CreateSubjectCertList (0, handle, & db_cert->derSubject,
    1076                 :         51 :                                                     PR_Now (), PR_FALSE);
    1077                 :         51 :   CERT_DestroyCertificate (db_cert);
    1078         [ -  + ]:         51 :   if (! certs)
    1079                 :            :     {
    1080                 :          0 :       nsscommon_error (_("NSS library failure in CERT_CreateSubjectCertList"));
    1081                 :          0 :       nssError ();
    1082                 :            :     }
    1083                 :            : 
    1084                 :         54 :   return certs;
    1085                 :            : }
    1086                 :            : 
    1087                 :            : static int
    1088                 :          8 : format_cert_validity_time (SECItem &vTime, char *timeString, size_t ts_size)
    1089                 :            : {
    1090                 :            :   int64 time;
    1091                 :            :   SECStatus secStatus;
    1092                 :            : 
    1093      [ +  -  - ]:          8 :   switch (vTime.type) {
    1094                 :            :   case siUTCTime:
    1095         [ +  - ]:          8 :     secStatus = DER_UTCTimeToTime (& time, & vTime);
    1096                 :          8 :     break;
    1097                 :            :   case siGeneralizedTime:
    1098         [ #  # ]:          0 :     secStatus = DER_GeneralizedTimeToTime (& time, & vTime);
    1099                 :          0 :     break;
    1100                 :            :   default:
    1101         [ #  # ]:          0 :     nsscommon_error (_("Could not decode certificate validity"));
    1102                 :          0 :     return 1;
    1103                 :            :   }
    1104         [ -  + ]:          8 :   if (secStatus != SECSuccess)
    1105                 :            :     {
    1106         [ #  # ]:          0 :       nsscommon_error (_("Could not decode certificate validity time"));
    1107                 :          0 :       return 1;
    1108                 :            :     }
    1109                 :            : 
    1110                 :            :   // Convert to local time.
    1111                 :            :   PRExplodedTime printableTime;
    1112         [ +  - ]:          8 :   PR_ExplodeTime (time, PR_GMTParameters, & printableTime);
    1113 [ +  - ][ -  + ]:          8 :   if (! PR_FormatTime (timeString, ts_size, "%a %b %d %H:%M:%S %Y", & printableTime))
    1114                 :            :     {
    1115         [ #  # ]:          0 :       nsscommon_error (_("Could not format certificate validity time"));
    1116                 :          0 :       return 1;
    1117                 :            :     }
    1118                 :            : 
    1119                 :          8 :   return 0;
    1120                 :            : }
    1121                 :            : 
    1122                 :            : static bool
    1123                 :          4 : cert_is_valid (CERTCertificate *cert)
    1124                 :            : {
    1125                 :            :   // Verify the the certificate is valid as an SSL server and as an object signer and that
    1126                 :            :   // it is valid now.
    1127         [ +  - ]:          4 :   CERTCertDBHandle *handle = CERT_GetDefaultCertDB ();
    1128         [ -  + ]:          4 :   assert (handle);
    1129                 :          4 :   SECCertificateUsage usage = certificateUsageSSLServer | certificateUsageObjectSigner;
    1130                 :            :   SECStatus secStatus = CERT_VerifyCertificate (handle, cert, PR_TRUE/*checkSig*/, usage,
    1131 [ +  - ][ +  - ]:          4 :                                                 PR_Now (), NULL, NULL/*log*/, & usage);
    1132                 :          4 :   return secStatus == SECSuccess;
    1133                 :            : }
    1134                 :            : 
    1135                 :            : static bool
    1136                 :          5 : cert_db_is_valid (const string &db_path, const string &nss_cert_name)
    1137                 :            : {
    1138                 :            :   // Make sure the given path exists.
    1139         [ +  + ]:          5 :   if (! file_exists (db_path))
    1140                 :            :     {
    1141         [ +  - ]:          1 :       log (_F("Certificate database %s does not exist", db_path.c_str ()));
    1142                 :          1 :       return false;
    1143                 :            :     }
    1144                 :            : 
    1145                 :            :   // If a 'pw' file exists, then this is an old database. Treat any certs as invalid.
    1146 [ +  - ][ -  + ]:          4 :   if (file_exists (db_path + "/pw"))
    1147                 :            :     {
    1148         [ #  # ]:          0 :       log (_F("Certificate database %s is obsolete", db_path.c_str ()));
    1149                 :          0 :       return false;
    1150                 :            :     }
    1151                 :            : 
    1152                 :            :   // Initialize the NSS libraries -- readonly
    1153                 :          4 :   SECStatus secStatus = nssInit (db_path.c_str ());
    1154         [ -  + ]:          4 :   if (secStatus != SECSuccess)
    1155                 :            :     {
    1156                 :            :       // Message already issued.
    1157                 :          0 :       return false;
    1158                 :            :     }
    1159                 :            : 
    1160                 :            :   // Obtain a list of our certs from the database.
    1161                 :          4 :   bool valid_p = false;
    1162                 :          4 :   CERTCertList *certs = get_cert_list_from_db (nss_cert_name);
    1163         [ -  + ]:          4 :   if (! certs)
    1164                 :            :     {
    1165         [ #  # ]:          0 :       log (_F("No certificate found in database %s", db_path.c_str ()));
    1166                 :          0 :       goto done;
    1167                 :            :     }
    1168                 :            : 
    1169         [ +  - ]:          4 :   log (_F("Certificate found in database %s", db_path.c_str ()));
    1170         [ +  - ]:          4 :   for (CERTCertListNode *node = CERT_LIST_HEAD (certs);
    1171                 :          4 :        ! CERT_LIST_END (node, certs);
    1172                 :            :        node = CERT_LIST_NEXT (node))
    1173                 :            :     {
    1174                 :            :       // The certificate we're working with.
    1175                 :          4 :       CERTCertificate *c = node->cert;
    1176                 :            : 
    1177                 :            :       // Print the validity dates of the certificate.
    1178                 :          4 :       CERTValidity &v = c->validity;
    1179                 :            :       char timeString[256];
    1180 [ +  - ][ +  - ]:          4 :       if (format_cert_validity_time (v.notBefore, timeString, sizeof (timeString)) == 0)
    1181 [ +  - ][ +  - ]:          4 :         log (_F("  Not Valid Before: %s UTC", timeString));
                 [ +  - ]
    1182 [ +  - ][ +  - ]:          4 :       if (format_cert_validity_time (v.notAfter, timeString, sizeof (timeString)) == 0)
    1183 [ +  - ][ +  - ]:          4 :         log (_F("  Not Valid After: %s UTC", timeString));
                 [ +  - ]
    1184                 :            : 
    1185                 :            :       // Now ask NSS to check the validity.
    1186 [ +  - ][ +  - ]:          4 :       if (cert_is_valid (c))
    1187                 :            :         {
    1188                 :            :           // The cert is valid. One valid cert is enough.
    1189 [ +  - ][ +  - ]:          4 :           log (_("Certificate is valid"));
                 [ +  - ]
    1190                 :          4 :           valid_p = true;
    1191                 :            :           break;
    1192                 :            :         }
    1193                 :            : 
    1194                 :            :       // The cert is not valid. Look for another one.
    1195 [ #  # ][ #  # ]:          0 :       log (_("Certificate is not valid"));
                 [ #  # ]
    1196                 :            :     }
    1197                 :          4 :   CERT_DestroyCertList (certs);
    1198                 :            : 
    1199                 :            :  done:
    1200                 :          4 :   nssCleanup (db_path.c_str ());
    1201                 :          5 :   return valid_p;
    1202                 :            : }
    1203                 :            : 
    1204                 :            : // Ensure that our certificate exists and is valid. Generate a new one if not.
    1205                 :            : int
    1206                 :          5 : check_cert (const string &db_path, const string &nss_cert_name, bool use_db_password)
    1207                 :            : {
    1208                 :            :   // Generate a new cert database if the current one does not exist or is not valid.
    1209         [ +  + ]:          5 :   if (! cert_db_is_valid (db_path, nss_cert_name))
    1210                 :            :     {
    1211 [ +  - ][ +  - ]:          1 :       if (gen_cert_db (db_path, "", use_db_password) != 0)
         [ +  - ][ -  + ]
    1212                 :            :         {
    1213                 :            :           // NSS message already issued.
    1214                 :          0 :           nsscommon_error (_("Unable to generate new certificate"));
    1215                 :          0 :           return 1;
    1216                 :            :         }
    1217                 :            :     }
    1218                 :          5 :   return 0;
    1219                 :            : }
    1220                 :            : 
    1221                 :          0 : void sign_file (
    1222                 :            :   const string &db_path,
    1223                 :            :   const string &nss_cert_name,
    1224                 :            :   const string &inputName,
    1225                 :            :   const string &outputName
    1226                 :            : ) {
    1227                 :            :   /* Get own certificate and private key. */
    1228 [ #  # ][ #  # ]:          0 :   CERTCertificate *cert = PK11_FindCertFromNickname (nss_cert_name.c_str (), NULL);
    1229         [ #  # ]:          0 :   if (cert == NULL)
    1230                 :            :     {
    1231                 :          0 :       nsscommon_error (_F("Unable to find certificate with nickname %s in %s.",
    1232 [ #  # ][ #  # ]:          0 :                           nss_cert_name.c_str (), db_path.c_str()));
         [ #  # ][ #  # ]
                 [ #  # ]
    1233         [ #  # ]:          0 :       nssError ();
    1234                 :            :       return;
    1235                 :            :     }
    1236                 :            : 
    1237                 :            :   // Predeclare these to keep C++ happy abount branches to 'done'.
    1238                 :            :   unsigned char buffer[4096];
    1239                 :          0 :   PRFileDesc *local_file_fd = NULL;
    1240                 :            :   PRInt32 numBytes;
    1241                 :            :   SECStatus secStatus;
    1242                 :            :   SGNContext *sgn;
    1243                 :            :   SECItem signedData;
    1244                 :            : 
    1245                 :            :   /* db_path.c_str () gets passed to nssPasswordCallback */
    1246 [ #  # ][ #  # ]:          0 :   SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert (cert, (void *)db_path.c_str ());
    1247         [ #  # ]:          0 :   if (privKey == NULL)
    1248                 :            :     {
    1249                 :          0 :       nsscommon_error (_F("Unable to obtain private key from the certificate with nickname %s in %s.",
    1250 [ #  # ][ #  # ]:          0 :                           nss_cert_name.c_str (), db_path.c_str()));
         [ #  # ][ #  # ]
                 [ #  # ]
    1251         [ #  # ]:          0 :       nssError ();
    1252                 :          0 :       goto done;
    1253                 :            :     }
    1254                 :            : 
    1255                 :            :   /* Sign the file. */
    1256                 :            :   /* Set up the signing context.  */
    1257         [ #  # ]:          0 :   sgn = SGN_NewContext (SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, privKey);
    1258         [ #  # ]:          0 :   if (! sgn) 
    1259                 :            :     {
    1260         [ #  # ]:          0 :       nsscommon_error (_("Could not create signing context"));
    1261         [ #  # ]:          0 :       nssError ();
    1262                 :            :       return;
    1263                 :            :     }
    1264         [ #  # ]:          0 :   secStatus = SGN_Begin (sgn);
    1265         [ #  # ]:          0 :   if (secStatus != SECSuccess)
    1266                 :            :     {
    1267         [ #  # ]:          0 :       nsscommon_error (_("Could not initialize signing context."));
    1268         [ #  # ]:          0 :       nssError ();
    1269                 :            :       return;
    1270                 :            :     }
    1271                 :            : 
    1272                 :            :   /* Now read the data and add it to the signature.  */
    1273 [ #  # ][ #  # ]:          0 :   local_file_fd = PR_Open (inputName.c_str(), PR_RDONLY, 0);
    1274         [ #  # ]:          0 :   if (local_file_fd == NULL)
    1275                 :            :     {
    1276 [ #  # ][ #  # ]:          0 :       nsscommon_error (_F("Could not open module file %s", inputName.c_str ()));
         [ #  # ][ #  # ]
    1277         [ #  # ]:          0 :       nssError ();
    1278                 :            :       return;
    1279                 :            :     }
    1280                 :            : 
    1281                 :          0 :   for (;;)
    1282                 :            :     {
    1283         [ #  # ]:          0 :       numBytes = PR_Read (local_file_fd, buffer, sizeof (buffer));
    1284         [ #  # ]:          0 :       if (numBytes == 0)
    1285                 :          0 :         break;  /* EOF */
    1286                 :            : 
    1287         [ #  # ]:          0 :       if (numBytes < 0)
    1288                 :            :         {
    1289 [ #  # ][ #  # ]:          0 :           nsscommon_error (_F("Error reading module file %s", inputName.c_str ()));
         [ #  # ][ #  # ]
    1290         [ #  # ]:          0 :           nssError ();
    1291                 :          0 :           goto done;
    1292                 :            :         }
    1293                 :            : 
    1294                 :            :       /* Add the data to the signature.  */
    1295         [ #  # ]:          0 :       secStatus = SGN_Update (sgn, buffer, numBytes);
    1296         [ #  # ]:          0 :       if (secStatus != SECSuccess)
    1297                 :            :         {
    1298 [ #  # ][ #  # ]:          0 :           nsscommon_error (_F("Error while signing module file %s", inputName.c_str ()));
         [ #  # ][ #  # ]
    1299         [ #  # ]:          0 :           nssError ();
    1300                 :          0 :           goto done;
    1301                 :            :         }
    1302                 :            :     }
    1303                 :            : 
    1304                 :            :   /* Complete the signature.  */
    1305         [ #  # ]:          0 :   secStatus = SGN_End (sgn, & signedData);
    1306         [ #  # ]:          0 :   if (secStatus != SECSuccess)
    1307                 :            :     {
    1308 [ #  # ][ #  # ]:          0 :       nsscommon_error (_F("Could not complete signature of module file %s", inputName.c_str ()));
         [ #  # ][ #  # ]
    1309         [ #  # ]:          0 :       nssError ();
    1310                 :          0 :       goto done;
    1311                 :            :     }
    1312                 :            : 
    1313         [ #  # ]:          0 :   SGN_DestroyContext (sgn, PR_TRUE);
    1314                 :            : 
    1315                 :            :   /* Now write the signed data to the output file.  */
    1316         [ #  # ]:          0 :   if(local_file_fd != NULL)
    1317         [ #  # ]:          0 :     PR_Close (local_file_fd);
    1318                 :            :   local_file_fd = PR_Open (outputName.c_str(), PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
    1319 [ #  # ][ #  # ]:          0 :                            PR_IRUSR | PR_IWUSR | PR_IRGRP | PR_IWGRP | PR_IROTH);
    1320         [ #  # ]:          0 :   if (local_file_fd == NULL)
    1321                 :            :     {
    1322 [ #  # ][ #  # ]:          0 :       nsscommon_error (_F("Could not open signature file %s", outputName.c_str ()));
         [ #  # ][ #  # ]
    1323         [ #  # ]:          0 :       nssError ();
    1324                 :          0 :       goto done;
    1325                 :            :     }
    1326                 :            : 
    1327         [ #  # ]:          0 :   numBytes = PR_Write (local_file_fd, signedData.data, signedData.len);
    1328 [ #  # ][ #  # ]:          0 :   if (numBytes < 0 || numBytes != (PRInt32)signedData.len)
    1329                 :            :     {
    1330 [ #  # ][ #  # ]:          0 :       nsscommon_error (_F("Error writing to signature file %s", outputName.c_str ()));
         [ #  # ][ #  # ]
    1331         [ #  # ]:          0 :       nssError ();
    1332                 :            :     }
    1333                 :            : 
    1334                 :            :  done:
    1335         [ #  # ]:          0 :   if (privKey)
    1336         [ #  # ]:          0 :     SECKEY_DestroyPrivateKey (privKey);
    1337         [ #  # ]:          0 :   CERT_DestroyCertificate (cert);
    1338         [ #  # ]:          0 :   if(local_file_fd != NULL)
    1339         [ #  # ]:          0 :     PR_Close (local_file_fd);
    1340 [ +  - ][ +  - ]:       8814 : }
    1341                 :            : 
    1342                 :            : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */

Generated by: LCOV version 1.9