1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/importer/nss_decryptor_system_nss.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <pk11pub.h>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <pk11sdr.h>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h"
1172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/file_path.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sys_string_conversions.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/nss_util.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochNSSDecryptor::NSSDecryptor() : is_nss_initialized_(false), db_slot_(NULL) {}
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochNSSDecryptor::~NSSDecryptor() {
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (db_slot_) {
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Deliberately leave the user db open, just in case we need to open more
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // than one, because there's an NSS bug with reopening user dbs.
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // https://bugzilla.mozilla.org/show_bug.cgi?id=506140
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // SECMOD_CloseUserDB(db_slot_);
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PK11_FreeSlot(db_slot_);
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool NSSDecryptor::Init(const FilePath& dll_path, const FilePath& db_path) {
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  crypto::EnsureNSSInit();
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  is_nss_initialized_ = true;
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string modspec =
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      StringPrintf("configDir='%s' tokenDescription='Firefox NSS database' "
3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                   "flags=readOnly", db_path.value().c_str());
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  db_slot_ = SECMOD_OpenUserDB(modspec.c_str());
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return db_slot_ != NULL;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This method is based on some NSS code in
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   security/nss/lib/pk11wrap/pk11sdr.c, CVS revision 1.22
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This code is copied because the implementation assumes the use of the
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// internal key slot for decryption, but we need to use another slot.
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The license block is:
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/* ***** BEGIN LICENSE BLOCK *****
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Version: MPL 1.1/GPL 2.0/LGPL 2.1
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The contents of this file are subject to the Mozilla Public License Version
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 1.1 (the "License"); you may not use this file except in compliance with
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * the License. You may obtain a copy of the License at
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * http://www.mozilla.org/MPL/
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Software distributed under the License is distributed on an "AS IS" basis,
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * for the specific language governing rights and limitations under the
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * License.
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The Original Code is the Netscape security libraries.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The Initial Developer of the Original Code is
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Netscape Communications Corporation.
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Portions created by the Initial Developer are Copyright (C) 1994-2000
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * the Initial Developer. All Rights Reserved.
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Contributor(s):
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *   thayes@netscape.com
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Alternatively, the contents of this file may be used under the terms of
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * either the GNU General Public License Version 2 or later (the "GPL"), or
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * in which case the provisions of the GPL or the LGPL are applicable instead
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * of those above. If you wish to allow use of your version of this file only
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * under the terms of either the GPL or the LGPL, and not to allow others to
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * use your version of this file under the terms of the MPL, indicate your
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * decision by deleting the provisions above and replace them with the notice
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * and other provisions required by the GPL or the LGPL. If you do not delete
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * the provisions above, a recipient may use your version of this file under
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * the terms of any one of the MPL, the GPL or the LGPL.
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * ***** END LICENSE BLOCK ***** */
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/*
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Data structure and template for encoding the result of an SDR operation
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *  This is temporary.  It should include the algorithm ID of the encryption
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *  mechanism
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct SDRResult
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch{
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECItem keyid;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECAlgorithmID alg;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECItem data;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef struct SDRResult SDRResult;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic SEC_ASN1Template g_template[] = {
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (SDRResult) },
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, keyid) },
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SDRResult, alg),
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, data) },
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  { 0 }
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic SECStatus
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochunpadBlock(SECItem *data, int blockSize, SECItem *result)
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch{
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECStatus rv = SECSuccess;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int padLength;
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int i;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->data = 0;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->len = 0;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /* Remove the padding from the end if the input data */
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data->len == 0 || data->len % blockSize  != 0) {
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = SECFailure;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    goto loser;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  padLength = data->data[data->len-1];
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (padLength > blockSize) { rv = SECFailure; goto loser; }
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /* verify padding */
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (i=data->len - padLength; static_cast<uint32>(i) < data->len; i++) {
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (data->data[i] != padLength) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = SECFailure;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        goto loser;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->len = data->len - padLength;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->data = (unsigned char *)PORT_Alloc(result->len);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!result->data) { rv = SECFailure; goto loser; }
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PORT_Memcpy(result->data, data->data, result->len);
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (padLength < 2) {
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return SECWouldBlock;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochloser:
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/* decrypt a block */
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic SECStatus
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochpk11Decrypt(PK11SlotInfo *slot, PLArenaPool *arena,
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            CK_MECHANISM_TYPE type, PK11SymKey *key,
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            SECItem *params, SECItem *in, SECItem *result)
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch{
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PK11Context *ctx = 0;
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECItem paddedResult;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECStatus rv;
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  paddedResult.len = 0;
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  paddedResult.data = 0;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ctx = PK11_CreateContextBySymKey(type, CKA_DECRYPT, key, params);
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ctx) { rv = SECFailure; goto loser; }
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  paddedResult.len = in->len;
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  paddedResult.data = static_cast<unsigned char*>(
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PORT_ArenaAlloc(arena, paddedResult.len));
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = PK11_CipherOp(ctx, paddedResult.data,
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        (int*)&paddedResult.len, paddedResult.len,
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        in->data, in->len);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != SECSuccess) goto loser;
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PK11_Finalize(ctx);
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /* Remove the padding */
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = unpadBlock(&paddedResult, PK11_GetBlockSize(type, 0), result);
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv) goto loser;
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochloser:
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (ctx) PK11_DestroyContext(ctx, PR_TRUE);
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSECStatus NSSDecryptor::PK11SDR_DecryptWithSlot(
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PK11SlotInfo* slot, SECItem* data, SECItem* result, void* cx) const {
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECStatus rv = SECSuccess;
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PK11SymKey *key = 0;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CK_MECHANISM_TYPE type;
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SDRResult sdrResult;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECItem *params = 0;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SECItem possibleResult = { siBuffer, NULL, 0 };
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PLArenaPool *arena = 0;
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!arena) { rv = SECFailure; goto loser; }
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /* Decode the incoming data */
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memset(&sdrResult, 0, sizeof sdrResult);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = SEC_QuickDERDecodeItem(arena, &sdrResult, g_template, data);
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != SECSuccess) goto loser;  /* Invalid format */
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /* Get the parameter values from the data */
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  params = PK11_ParamFromAlgid(&sdrResult.alg);
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!params) { rv = SECFailure; goto loser; }
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /* Use triple-DES (Should look up the algorithm) */
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  type = CKM_DES3_CBC;
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  key = PK11_FindFixedKey(slot, type, &sdrResult.keyid, cx);
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!key) {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = SECFailure;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = pk11Decrypt(slot, arena, type, key, params,
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     &sdrResult.data, result);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /*
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   * if the pad value was too small (1 or 2), then it's statistically
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   * 'likely' that (1 in 256) that we may not have the correct key.
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   * Check the other keys for a better match. If we find none, use
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   * this result.
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   */
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv == SECWouldBlock)
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    possibleResult = *result;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /*
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   * handle the case where your key indicies may have been broken
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   */
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != SECSuccess) {
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PK11SymKey *keyList = PK11_ListFixedKeysInSlot(slot, NULL, cx);
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PK11SymKey *testKey = NULL;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PK11SymKey *nextKey = NULL;
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (testKey = keyList; testKey;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         testKey = PK11_GetNextSymKey(testKey)) {
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      rv = pk11Decrypt(slot, arena, type, testKey, params,
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       &sdrResult.data, result);
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (rv == SECSuccess)
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      /* found a close match. If it's our first remember it */
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (rv == SECWouldBlock) {
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (possibleResult.data) {
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          /* this is unlikely but possible. If we hit this condition,
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           * we have no way of knowing which possibility to prefer.
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           * in this case we just match the key the application
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           * thought was the right one */
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          SECITEM_ZfreeItem(result, PR_FALSE);
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        } else {
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          possibleResult = *result;
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    /* free the list */
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (testKey = keyList; testKey; testKey = nextKey) {
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         nextKey = PK11_GetNextSymKey(testKey);
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PK11_FreeSymKey(testKey);
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /* we didn't find a better key, use the one with a small pad value */
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((rv != SECSuccess) && (possibleResult.data)) {
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *result = possibleResult;
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    possibleResult.data = NULL;
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = SECSuccess;
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loser:
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (arena) PORT_FreeArena(arena, PR_TRUE);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (key) PK11_FreeSymKey(key);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (params) SECITEM_ZfreeItem(params, PR_TRUE);
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (possibleResult.data) SECITEM_ZfreeItem(&possibleResult, PR_FALSE);
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
270