~ubuntu-branches/ubuntu/natty/enigmail/natty-security

« back to all changes in this revision

Viewing changes to extensions/enigmail/package/enigmailCommon.jsm

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-08-20 17:18:02 UTC
  • mfrom: (0.13.4)
  • Revision ID: package-import@ubuntu.com-20120820171802-wy0l2jvokcfrdwc1
Tags: 2:1.4.4-0ubuntu0.11.04.1
* New upstream release v1.4.4 to support Thunderbird 15
  - LP: #1042165

Show diffs side-by-side

added added

removed removed

Lines of Context:
985
985
    return text;
986
986
  },
987
987
 
988
 
  parseErrorOutput: function (errOutput, statusFlagsObj, statusMsgObj, blockSeparationObj)
 
988
  parseErrorOutput: function (errOutput, retStatusObj)
989
989
  {
990
990
 
991
991
    this.WRITE_LOG("enigmailCommon.jsm: parseErrorOutput:\n");
1002
1002
    var detectedCard = null;
1003
1003
    var requestedCard = null;
1004
1004
    var errorMsg = "";
1005
 
    statusMsgObj.value = "";
 
1005
    retStatusObj.statusMsg = "";
1006
1006
 
1007
1007
    var statusPat = /^\[GNUPG:\] /;
1008
1008
    var statusFlags = 0;
1043
1043
            statusFlags |= Ci.nsIEnigmail.DISPLAY_MESSAGE;
1044
1044
            flag = 0;
1045
1045
            this.DEBUG_LOG("enigmailCommon.jsm: detected invalid sender: "+lineSplit[2]+" / code: "+lineSplit[1]+"\n");
1046
 
            statusMsgObj.value += this.getString("gnupg.invalidKey.desc", [ lineSplit[2] ]);
 
1046
            retStatusObj.statusMsg += this.getString("gnupg.invalidKey.desc", [ lineSplit[2] ]);
1047
1047
          }
1048
1048
 
1049
1049
          if (flag)
1050
1050
            statusFlags |= flag;
1051
1051
 
1052
 
          //this.DEBUG_LOG("enigmailCommon.jsm: parseErrorOutput: status match '+matches[1]+"\n");
1053
1052
        }
1054
1053
 
1055
1054
      } else {
1059
1058
 
1060
1059
    // detect forged message insets
1061
1060
 
1062
 
    if (! blockSeparationObj) {
1063
 
      blockSeparationObj = new Object();
1064
 
    }
1065
 
    blockSeparationObj.value = "";
 
1061
    retStatusObj.blockSeparation = "";
1066
1062
 
1067
1063
    var plaintextCount=0;
1068
1064
    var withinCryptoMsg = false;
1082
1078
        if ((statusArray.length > j+1) && (statusArray[j+1].search(plaintextLengthPat) == 0)) {
1083
1079
          matches = statusArray[j+1].match(/(\w+) (\d+)/);
1084
1080
          if (matches.length>=3) {
1085
 
            blockSeparationObj.value += (withinCryptoMsg ? "1" : "0") + ":"+matches[2]+" ";
 
1081
            retStatusObj.blockSeparation += (withinCryptoMsg ? "1" : "0") + ":"+matches[2]+" ";
1086
1082
          }
1087
1083
        }
1088
1084
        else {
1089
1085
          // strange: we got PLAINTEXT XX, but not PLAINTEXT_LENGTH XX
1090
 
          blockSeparationObj.value += (withinCryptoMsg ? "1" : "0") + ":0 ";
 
1086
          retStatusObj.blockSeparation += (withinCryptoMsg ? "1" : "0") + ":0 ";
1091
1087
        }
1092
1088
      }
1093
1089
    }
1094
1090
 
1095
1091
    if (plaintextCount > 1) statusFlags |= (Ci.nsIEnigmail.PARTIALLY_PGP | Ci.nsIEnigmail.DECRYPTION_FAILED | Ci.nsIEnigmail.BAD_SIGNATURE);
1096
1092
 
1097
 
    blockSeparationObj.value = blockSeparationObj.value.replace(/ $/, "");
1098
 
    statusFlagsObj.value = statusFlags;
1099
 
    if (statusMsgObj.value.length == 0) statusMsgObj.value = statusArray.join("\n");
 
1093
    retStatusObj.blockSeparation = retStatusObj.blockSeparation.replace(/ $/, "");
 
1094
    retStatusObj.statusFlags = statusFlags;
 
1095
    if (retStatusObj.statusMsg.length == 0) retStatusObj.statusMsg = statusArray.join("\n");
1100
1096
    if (errorMsg.length == 0)
1101
1097
      errorMsg = errArray.map(this.convertFromGpg, this).join("\n");
1102
1098
 
1818
1814
 
1819
1815
    var expired = ((currentTime - _lastActiveTime) >= delayMillisec);
1820
1816
 
1821
 
  //  this.DEBUG_LOG("enigmail.js: Enigmail.haveCachedPassphrase: ")
 
1817
  //  this.DEBUG_LOG("enigmail.jsm: haveCachedPassphrase: ")
1822
1818
  //  this.DEBUG_LOG("currentTime="+currentTime+", _lastActiveTime="+this._lastActiveTime+", expired="+expired+"\n");
1823
1819
 
1824
1820
    if (expired && (_passwdAccessTimes <= 0)) {
1838
1834
    // Update last active time
1839
1835
    var curDate = new Date();
1840
1836
    _lastActiveTime = curDate.getTime();
1841
 
    // this.DEBUG_LOG("enigmail.js: Enigmail.stillActive: _lastActiveTime="+this._lastActiveTime+"\n");
 
1837
    // this.DEBUG_LOG("enigmail.jsm: stillActive: _lastActiveTime="+this._lastActiveTime+"\n");
1842
1838
  },
1843
1839
 
1844
1840
  clearCachedPassphrase: function () {
1845
 
    this.DEBUG_LOG("enigmail.js: Enigmail.clearCachedPassphrase: \n");
 
1841
    this.DEBUG_LOG("enigmail.jsm: clearCachedPassphrase: \n");
1846
1842
 
1847
1843
    gCachedPassphrase = null;
1848
1844
  },
1884
1880
      gCacheTimer.init(this, delayMillisec,
1885
1881
                        createTimerType);
1886
1882
 
1887
 
      this.DEBUG_LOG("enigmail.js: Enigmail.setCachedPassphrase: gCacheTimer="+gCacheTimer+"\n");
 
1883
      this.DEBUG_LOG("enigmail.jsm: setCachedPassphrase: gCacheTimer="+gCacheTimer+"\n");
1888
1884
    }
1889
1885
  },
1890
1886
 
1972
1968
  },
1973
1969
 
1974
1970
  getLocalFileApi: function () {
1975
 
    if ("nsILocalFile" in Ci) {
1976
 
      return Ci.nsILocalFile;
1977
 
    }
1978
 
    else
1979
 
      return Ci.nsIFile;
 
1971
    return Ci.nsIFile;
 
1972
  },
 
1973
 
 
1974
 
 
1975
  // Extract public key from Status Message
 
1976
  extractPubkey: function (statusMsg) {
 
1977
    var keyId = null;
 
1978
    var matchb = statusMsg.match(/(^|\n)NO_PUBKEY (\w{8})(\w{8})/);
 
1979
 
 
1980
    if (matchb && (matchb.length > 3)) {
 
1981
      this.DEBUG_LOG("enigmail.js: Enigmail.extractPubkey: NO_PUBKEY 0x"+matchb[3]+"\n");
 
1982
      keyId = matchb[2]+matchb[3];
 
1983
    }
 
1984
 
 
1985
    return keyId;
 
1986
  },
 
1987
 
 
1988
 
 
1989
  /* listener object:
 
1990
      stdin(pipe),
 
1991
      stdout(data),
 
1992
      stderr(data),
 
1993
      done(exitCode */
 
1994
 
 
1995
  execStart: function (command, args, needPassphrase, domWindow, listener, statusFlagsObj) {
 
1996
    this.WRITE_LOG("enigmailCommon.jsm: execStart: command = "+this.printCmdLine(command, args)+", needPassphrase="+needPassphrase+", domWindow="+domWindow+", listener="+listener+"\n");
 
1997
 
 
1998
    if (! listener) listener = {};
 
1999
 
 
2000
    statusFlagsObj.value = 0;
 
2001
 
 
2002
    var passphrase = null;
 
2003
    var useAgentObj = {value: false};
 
2004
 
 
2005
    if (needPassphrase) {
 
2006
      args = args.concat(this.passwdCommand());
 
2007
 
 
2008
      var passwdObj = new Object();
 
2009
 
 
2010
      if (!this.getPassphrase(domWindow, passwdObj, useAgentObj, 0)) {
 
2011
         this.ERROR_LOG("enigmailCommon.jsm: execStart: Error - no passphrase supplied\n");
 
2012
 
 
2013
         statusFlagsObj.value |= nsIEnigmail.MISSING_PASSPHRASE;
 
2014
         return null;
 
2015
      }
 
2016
 
 
2017
      passphrase = passwdObj.value;
 
2018
    }
 
2019
 
 
2020
    this.CONSOLE_LOG("enigmail> "+this.printCmdLine(command, args)+"\n");
 
2021
 
 
2022
    try {
 
2023
      proc = subprocess.call({
 
2024
        command:     command,
 
2025
        arguments:   args,
 
2026
        environment: this.getEnvList(),
 
2027
        charset: null,
 
2028
        stdin: function (pipe) {
 
2029
          if (needPassphrase) {
 
2030
            // Write to child STDIN
 
2031
            // (ignore errors, because child may have exited already, closing STDIN)
 
2032
            try {
 
2033
              if (EnigmailCommon.requirePassword()) {
 
2034
                 pipe.write(passphrase+"\n");
 
2035
              }
 
2036
            } catch (ex) {}
 
2037
          }
 
2038
 
 
2039
          if (listener.stdin) listener.stdin(pipe);
 
2040
        },
 
2041
        stdout: function(data) { listener.stdout(data) },
 
2042
        stderr: function(data) { listener.stderr(data) },
 
2043
        done: function(result) {
 
2044
          try {
 
2045
            listener.done(result.exitCode);
 
2046
          }
 
2047
          catch (ex) {
 
2048
            EnigmailCommon.writeException("enigmailCommon.jsm", ex);
 
2049
          }
 
2050
        },
 
2051
        mergeStderr: false
 
2052
      });
 
2053
    } catch (ex) {
 
2054
      this.CONSOLE_LOG("enigmail.jsm: execStart: Error - Failed to start PipeTransport\n");
 
2055
      this.ERROR_LOG("enigmailCommon.jsm: execStart: subprocess.call failed with '"+ex.toString()+"'\n");
 
2056
      return null;
 
2057
    }
 
2058
 
 
2059
    return proc;
 
2060
  },
 
2061
 
 
2062
  decryptMessageStart: function (win, verifyOnly, listener,
 
2063
                                 statusFlagsObj, errorMsgObj) {
 
2064
    this.DEBUG_LOG("enigmailCommon.jsm: decryptMessageStart: verifyOnly="+verifyOnly+"\n");
 
2065
 
 
2066
    this.getService(win);
 
2067
    if (! (this.enigmailSvc)) {
 
2068
      this.ERROR_LOG("enigmail.jsm: decryptMessageStart: not yet initialized\n");
 
2069
      errorMsgObj.value = this.getString("notInit");
 
2070
      return null;
 
2071
    }
 
2072
 
 
2073
    if (gKeygenProcess) {
 
2074
      errorMsgObj.value = this.getString("notComplete");
 
2075
      return null;
 
2076
    }
 
2077
 
 
2078
    var args = this.getAgentArgs(true);
 
2079
 
 
2080
    var keyserver = this.getPref("autoKeyRetrieve");
 
2081
    if (keyserver && keyserver != "") {
 
2082
      args.push("--keyserver-options");
 
2083
      var keySrvArgs="auto-key-retrieve";
 
2084
      var srvProxy = this.getHttpProxy(keyserver);
 
2085
      if (srvProxy) {
 
2086
        keySrvArgs += ",http-proxy="+srvProxy;
 
2087
      }
 
2088
      args.push(keySrvArgs);
 
2089
      args.push("--keyserver");
 
2090
      args.push(keyserver);
 
2091
    }
 
2092
 
 
2093
    if (verifyOnly) {
 
2094
      args.push("--verify");
 
2095
 
 
2096
    } else {
 
2097
      args.push("--decrypt");
 
2098
    }
 
2099
 
 
2100
    var proc = this.execStart(this.enigmailSvc.agentPath, args, !verifyOnly, win,
 
2101
                              listener, statusFlagsObj);
 
2102
 
 
2103
    if (statusFlagsObj.value & nsIEnigmail.MISSING_PASSPHRASE) {
 
2104
      this.ERROR_LOG("enigmailCommon.jsm: decryptMessageStart: Error - no passphrase supplied\n");
 
2105
 
 
2106
      errorMsgObj.value = this.getString("noPassphrase");
 
2107
      return null;
 
2108
    }
 
2109
 
 
2110
    return proc;
 
2111
  },
 
2112
 
 
2113
  decryptMessageEnd: function (stderrStr, exitCode, outputLen, verifyOnly, noOutput, uiFlags, retStatusObj) {
 
2114
    this.DEBUG_LOG("enigmail.jsm: decryptMessageEnd: uiFlags="+uiFlags+", verifyOnly="+verifyOnly+", noOutput="+noOutput+"\n");
 
2115
 
 
2116
    this.DEBUG_LOG("enigmail.jsm: decryptMessageEnd: stderrStr="+stderrStr+"\n");
 
2117
    var interactive = uiFlags & nsIEnigmail.UI_INTERACTIVE;
 
2118
    var pgpMime     = uiFlags & nsIEnigmail.UI_PGP_MIME;
 
2119
    var allowImport = uiFlags & nsIEnigmail.UI_ALLOW_KEY_IMPORT;
 
2120
    var unverifiedEncryptedOK = uiFlags & nsIEnigmail.UI_UNVERIFIED_ENC_OK;
 
2121
    var j;
 
2122
 
 
2123
    retStatusObj.statusFlags = 0;
 
2124
    retStatusObj.errorMsg    = "";
 
2125
    retStatusObj.blockSeparation  = "";
 
2126
 
 
2127
    var errorMsg = this.parseErrorOutput(stderrStr, retStatusObj);
 
2128
 
 
2129
    if (pgpMime) {
 
2130
      retStatusObj.statusFlags |= verifyOnly ? nsIEnigmail.PGP_MIME_SIGNED
 
2131
                                         : nsIEnigmail.PGP_MIME_ENCRYPTED;
 
2132
    }
 
2133
 
 
2134
    var statusMsg = retStatusObj.statusMsg;
 
2135
    exitCode = this.fixExitCode(exitCode, retStatusObj.statusFlags);
 
2136
    if ((exitCode == 0) && !noOutput && !outputLen &&
 
2137
        ((retStatusObj.statusFlags & (gStatusFlags.DECRYPTION_OKAY | gStatusFlags.GOODSIG)) == 0)) {
 
2138
      exitCode = -1;
 
2139
    }
 
2140
 
 
2141
    if (exitCode == 0) {
 
2142
      // Normal return
 
2143
      var errLines, goodSignPat, badSignPat, keyExpPat, revKeyPat, validSigPat;
 
2144
 
 
2145
      if (statusMsg) {
 
2146
          errLines = statusMsg.split(/\r?\n/);
 
2147
 
 
2148
          goodSignPat =   /GOODSIG (\w{16}) (.*)$/i;
 
2149
          badSignPat  =    /BADSIG (\w{16}) (.*)$/i;
 
2150
          keyExpPat   = /EXPKEYSIG (\w{16}) (.*)$/i
 
2151
          revKeyPat   = /REVKEYSIG (\w{16}) (.*)$/i;
 
2152
          validSigPat =  /VALIDSIG (\w+) (.*) (\d+) (.*)/i;
 
2153
 
 
2154
      } else {
 
2155
          errLines = stderrStr.value.split(/\r?\n/);
 
2156
 
 
2157
          goodSignPat = /Good signature from (user )?"(.*)"\.?/i;
 
2158
          badSignPat  =  /BAD signature from (user )?"(.*)"\.?/i;
 
2159
          keyExpPat   = /This key has expired/i;
 
2160
          revKeyPat   = /This key has been revoked/i;
 
2161
          validSigPat = /dummy-not-used/i;
 
2162
      }
 
2163
 
 
2164
      retStatusObj.errorMsg = "";
 
2165
 
 
2166
      var matches;
 
2167
 
 
2168
      var signed = false;
 
2169
      var goodSignature;
 
2170
 
 
2171
      var userId = "";
 
2172
      var keyId = "";
 
2173
      var sigDetails = "";
 
2174
 
 
2175
      for (j=0; j<errLines.length; j++) {
 
2176
        matches = errLines[j].match(badSignPat);
 
2177
 
 
2178
        if (matches && (matches.length > 2)) {
 
2179
          signed = true;
 
2180
          goodSignature = false;
 
2181
          userId = matches[2];
 
2182
          keyId = matches[1];
 
2183
          break;
 
2184
        }
 
2185
 
 
2186
        matches = errLines[j].match(revKeyPat);
 
2187
 
 
2188
        if (matches && (matches.length > 2)) {
 
2189
          signed = true;
 
2190
          goodSignature = true;
 
2191
          userId = matches[2];
 
2192
          keyId = matches[1];
 
2193
          break;
 
2194
        }
 
2195
 
 
2196
        matches = errLines[j].match(goodSignPat);
 
2197
 
 
2198
        if (matches && (matches.length > 2)) {
 
2199
          signed = true;
 
2200
          goodSignature = true;
 
2201
          userId = matches[2];
 
2202
          keyId = matches[1];
 
2203
          break;
 
2204
        }
 
2205
 
 
2206
        matches = errLines[j].match(keyExpPat);
 
2207
 
 
2208
        if (matches && (matches.length > 2)) {
 
2209
          signed = true;
 
2210
          goodSignature = true;
 
2211
          userId = matches[2];
 
2212
          keyId = matches[1];
 
2213
 
 
2214
          break;
 
2215
        }
 
2216
      }
 
2217
 
 
2218
      if (goodSignature) {
 
2219
        for (var j=0; j<errLines.length; j++) {
 
2220
          matches = errLines[j].match(validSigPat);
 
2221
 
 
2222
          if (matches && (matches.length > 4))
 
2223
            keyId = matches[4].substr(-16); // in case of several subkeys refer to the main key ID
 
2224
 
 
2225
          if (matches && (matches.length > 2)) {
 
2226
            sigDetails = errLines[j].substr(9);
 
2227
            break;
 
2228
          }
 
2229
        }
 
2230
      }
 
2231
 
 
2232
      //try {
 
2233
        if (userId && keyId && this.prefBranch.getBoolPref("displaySecondaryUid")) {
 
2234
          let uids = this.enigmailSvc.getKeyDetails(keyId, true);
 
2235
          if (uids) {
 
2236
            userId = uids;
 
2237
          }
 
2238
        }
 
2239
      //}
 
2240
      //catch (ex) {}
 
2241
 
 
2242
      if (userId) {
 
2243
        userId = this.convertToUnicode(userId, "UTF-8");
 
2244
      }
 
2245
 
 
2246
      retStatusObj.userId = userId;
 
2247
      retStatusObj.keyId = keyId;
 
2248
      retStatusObj.sigDetails = sigDetails;
 
2249
 
 
2250
      if (signed) {
 
2251
        var trustPrefix = "";
 
2252
 
 
2253
        if (retStatusObj.statusFlags & nsIEnigmail.UNTRUSTED_IDENTITY) {
 
2254
          trustPrefix += this.getString("prefUntrusted")+" ";
 
2255
        }
 
2256
 
 
2257
        if (retStatusObj.statusFlags & nsIEnigmail.REVOKED_KEY) {
 
2258
          trustPrefix += this.getString("prefRevoked")+" ";
 
2259
        }
 
2260
 
 
2261
        if (retStatusObj.statusFlags & nsIEnigmail.EXPIRED_KEY_SIGNATURE) {
 
2262
          trustPrefix += this.getString("prefExpiredKey")+" ";
 
2263
 
 
2264
        } else if (retStatusObj.statusFlags & nsIEnigmail.EXPIRED_SIGNATURE) {
 
2265
          trustPrefix += this.getString("prefExpired")+" ";
 
2266
        }
 
2267
 
 
2268
        if (goodSignature) {
 
2269
          retStatusObj.errorMsg = trustPrefix + this.getString("prefGood", [userId]) /* + ", " +
 
2270
                this.getString("keyId") + " 0x" + keyId.substring(8,16); */
 
2271
        } else {
 
2272
          retStatusObj.errorMsg = trustPrefix + this.getString("prefBad", [userId]) /*+ ", " +
 
2273
                this.getString("keyId") + " 0x" + keyId.substring(8,16); */
 
2274
          if (!exitCode)
 
2275
            exitCode = 1;
 
2276
        }
 
2277
      }
 
2278
 
 
2279
      if (retStatusObj.statusFlags & nsIEnigmail.UNVERIFIED_SIGNATURE) {
 
2280
        retStatusObj.keyId = this.extractPubkey(statusMsg)
 
2281
      }
 
2282
 
 
2283
      return exitCode;
 
2284
    }
 
2285
 
 
2286
 
 
2287
    if (retStatusObj.statusFlags & nsIEnigmail.BAD_PASSPHRASE) {
 
2288
      // "Unremember" passphrase on decryption failure
 
2289
      this.clearCachedPassphrase();
 
2290
    }
 
2291
 
 
2292
    var pubKeyId;
 
2293
 
 
2294
    if (retStatusObj.statusFlags & nsIEnigmail.UNVERIFIED_SIGNATURE) {
 
2295
      // Unverified signature
 
2296
      retStatusObj.keyId = this.extractPubkey(statusMsg);
 
2297
 
 
2298
      if (retStatusObj.statusFlags & nsIEnigmail.DECRYPTION_OKAY) {
 
2299
        exitCode=0;
 
2300
      }
 
2301
 
 
2302
    }
 
2303
 
 
2304
    if (exitCode != 0) {
 
2305
      // Error processing
 
2306
      this.DEBUG_LOG("enigmail.jsm: decryptMessageEnd: command execution exit code: "+exitCode+"\n");
 
2307
    }
 
2308
 
 
2309
/* MOVED
 
2310
    if (cmdErrorMsgObj.value) {
 
2311
      errorMsgObj.value = this.agentType + " " + this.getString("cmdLine");
 
2312
      errorMsgObj.value += "\n" + cmdLineObj.value;
 
2313
      errorMsgObj.value += "\n" + cmdErrorMsgObj.value;
 
2314
    }
 
2315
*/
 
2316
    return exitCode;
1980
2317
  }
1981
2318
};
1982
2319