15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/utility/importer/nss_decryptor_system_nss.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pk11pub.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pk11sdr.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/nss_util.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NSSDecryptor::NSSDecryptor() : is_nss_initialized_(false), db_slot_(NULL) {}
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NSSDecryptor::~NSSDecryptor() {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_slot_) {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Deliberately leave the user db open, just in case we need to open more
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // than one, because there's an NSS bug with reopening user dbs.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // https://bugzilla.mozilla.org/show_bug.cgi?id=506140
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // SECMOD_CloseUserDB(db_slot_);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PK11_FreeSlot(db_slot_);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NSSDecryptor::Init(const base::FilePath& dll_path,
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        const base::FilePath& db_path) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  crypto::EnsureNSSInit();
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_nss_initialized_ = true;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string modspec =
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::StringPrintf(
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "configDir='%s' tokenDescription='Firefox NSS database' "
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "flags=readOnly",
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          db_path.value().c_str());
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_slot_ = SECMOD_OpenUserDB(modspec.c_str());
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_slot_ != NULL;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method is based on some NSS code in
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   security/nss/lib/pk11wrap/pk11sdr.c, CVS revision 1.22
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This code is copied because the implementation assumes the use of the
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// internal key slot for decryption, but we need to use another slot.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The license block is:
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* ***** BEGIN LICENSE BLOCK *****
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Version: MPL 1.1/GPL 2.0/LGPL 2.1
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The contents of this file are subject to the Mozilla Public License Version
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1.1 (the "License"); you may not use this file except in compliance with
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the License. You may obtain a copy of the License at
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://www.mozilla.org/MPL/
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Software distributed under the License is distributed on an "AS IS" basis,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * for the specific language governing rights and limitations under the
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The Original Code is the Netscape security libraries.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The Initial Developer of the Original Code is
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Netscape Communications Corporation.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Portions created by the Initial Developer are Copyright (C) 1994-2000
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the Initial Developer. All Rights Reserved.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Contributor(s):
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   thayes@netscape.com
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Alternatively, the contents of this file may be used under the terms of
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * either the GNU General Public License Version 2 or later (the "GPL"), or
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in which case the provisions of the GPL or the LGPL are applicable instead
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of those above. If you wish to allow use of your version of this file only
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * under the terms of either the GPL or the LGPL, and not to allow others to
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * use your version of this file under the terms of the MPL, indicate your
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * decision by deleting the provisions above and replace them with the notice
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and other provisions required by the GPL or the LGPL. If you do not delete
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the provisions above, a recipient may use your version of this file under
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the terms of any one of the MPL, the GPL or the LGPL.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ***** END LICENSE BLOCK ***** */
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Data structure and template for encoding the result of an SDR operation
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *  This is temporary.  It should include the algorithm ID of the encryption
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *  mechanism
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct SDRResult
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem keyid;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECAlgorithmID alg;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem data;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct SDRResult SDRResult;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SEC_ASN1Template g_template[] = {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (SDRResult) },
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, keyid) },
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SDRResult, alg),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, data) },
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { 0 }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SECStatus
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unpadBlock(SECItem *data, int blockSize, SECItem *result)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = SECSuccess;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int padLength;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->data = 0;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->len = 0;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Remove the padding from the end if the input data */
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data->len == 0 || data->len % blockSize  != 0) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = SECFailure;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto loser;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  padLength = data->data[data->len-1];
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (padLength > blockSize) { rv = SECFailure; goto loser; }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* verify padding */
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i=data->len - padLength; static_cast<uint32>(i) < data->len; i++) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (data->data[i] != padLength) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rv = SECFailure;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        goto loser;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->len = data->len - padLength;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->data = (unsigned char *)PORT_Alloc(result->len);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result->data) { rv = SECFailure; goto loser; }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PORT_Memcpy(result->data, data->data, result->len);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (padLength < 2) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SECWouldBlock;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)loser:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* decrypt a block */
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SECStatus
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pk11Decrypt(PK11SlotInfo *slot, PLArenaPool *arena,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            CK_MECHANISM_TYPE type, PK11SymKey *key,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SECItem *params, SECItem *in, SECItem *result)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PK11Context *ctx = 0;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem paddedResult;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paddedResult.len = 0;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paddedResult.data = 0;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ctx = PK11_CreateContextBySymKey(type, CKA_DECRYPT, key, params);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ctx) { rv = SECFailure; goto loser; }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paddedResult.len = in->len;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paddedResult.data = static_cast<unsigned char*>(
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PORT_ArenaAlloc(arena, paddedResult.len));
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rv = PK11_CipherOp(ctx, paddedResult.data,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        (int*)&paddedResult.len, paddedResult.len,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        in->data, in->len);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) goto loser;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PK11_Finalize(ctx);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Remove the padding */
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rv = unpadBlock(&paddedResult, PK11_GetBlockSize(type, 0), result);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv) goto loser;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)loser:
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ctx) PK11_DestroyContext(ctx, PR_TRUE);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus NSSDecryptor::PK11SDR_DecryptWithSlot(
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PK11SlotInfo* slot, SECItem* data, SECItem* result, void* cx) const {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = SECSuccess;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PK11SymKey *key = 0;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CK_MECHANISM_TYPE type;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SDRResult sdrResult;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem *params = 0;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem possibleResult = { siBuffer, NULL, 0 };
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLArenaPool *arena = 0;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!arena) { rv = SECFailure; goto loser; }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Decode the incoming data */
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&sdrResult, 0, sizeof sdrResult);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rv = SEC_QuickDERDecodeItem(arena, &sdrResult, g_template, data);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) goto loser;  /* Invalid format */
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Get the parameter values from the data */
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params = PK11_ParamFromAlgid(&sdrResult.alg);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!params) { rv = SECFailure; goto loser; }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Use triple-DES (Should look up the algorithm) */
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  type = CKM_DES3_CBC;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key = PK11_FindFixedKey(slot, type, &sdrResult.keyid, cx);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!key) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = SECFailure;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = pk11Decrypt(slot, arena, type, key, params,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     &sdrResult.data, result);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /*
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * if the pad value was too small (1 or 2), then it's statistically
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * 'likely' that (1 in 256) that we may not have the correct key.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * Check the other keys for a better match. If we find none, use
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * this result.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv == SECWouldBlock)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    possibleResult = *result;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /*
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * handle the case where your key indicies may have been broken
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PK11SymKey *keyList = PK11_ListFixedKeysInSlot(slot, NULL, cx);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PK11SymKey *testKey = NULL;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PK11SymKey *nextKey = NULL;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (testKey = keyList; testKey;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         testKey = PK11_GetNextSymKey(testKey)) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rv = pk11Decrypt(slot, arena, type, testKey, params,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &sdrResult.data, result);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (rv == SECSuccess)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* found a close match. If it's our first remember it */
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (rv == SECWouldBlock) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (possibleResult.data) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          /* this is unlikely but possible. If we hit this condition,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           * we have no way of knowing which possibility to prefer.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           * in this case we just match the key the application
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           * thought was the right one */
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SECITEM_ZfreeItem(result, PR_FALSE);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          possibleResult = *result;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* free the list */
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (testKey = keyList; testKey; testKey = nextKey) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         nextKey = PK11_GetNextSymKey(testKey);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PK11_FreeSymKey(testKey);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* we didn't find a better key, use the one with a small pad value */
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((rv != SECSuccess) && (possibleResult.data)) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = possibleResult;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    possibleResult.data = NULL;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = SECSuccess;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loser:
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (arena) PORT_FreeArena(arena, PR_TRUE);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key) PK11_FreeSymKey(key);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params) SECITEM_ZfreeItem(params, PR_TRUE);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (possibleResult.data) SECITEM_ZfreeItem(&possibleResult, PR_FALSE);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
273