1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "crypto/signature_verifier.h"
6
7#include <cryptohi.h>
8#include <keyhi.h>
9#include <pk11pub.h>
10#include <secerr.h>
11#include <sechash.h>
12#include <stdlib.h>
13
14#include "base/logging.h"
15#include "crypto/nss_util.h"
16#include "crypto/third_party/nss/chromium-nss.h"
17
18namespace crypto {
19
20namespace {
21
22HASH_HashType ToNSSHashType(SignatureVerifier::HashAlgorithm hash_alg) {
23  switch (hash_alg) {
24    case SignatureVerifier::SHA1:
25      return HASH_AlgSHA1;
26    case SignatureVerifier::SHA256:
27      return HASH_AlgSHA256;
28  }
29  return HASH_AlgNULL;
30}
31
32SECStatus VerifyRSAPSS_End(SECKEYPublicKey* public_key,
33                           HASHContext* hash_context,
34                           HASH_HashType mask_hash_alg,
35                           unsigned int salt_len,
36                           const unsigned char* signature,
37                           unsigned int signature_len) {
38  unsigned int hash_len = HASH_ResultLenContext(hash_context);
39  std::vector<unsigned char> hash(hash_len);
40  HASH_End(hash_context, &hash[0], &hash_len, hash.size());
41
42  unsigned int modulus_len = SECKEY_PublicKeyStrength(public_key);
43  if (signature_len != modulus_len) {
44    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
45    return SECFailure;
46  }
47  std::vector<unsigned char> enc(signature_len);
48  SECStatus rv = PK11_PubEncryptRaw(public_key, &enc[0],
49                                    const_cast<unsigned char*>(signature),
50                                    signature_len, NULL);
51  if (rv != SECSuccess) {
52    LOG(WARNING) << "PK11_PubEncryptRaw failed";
53    return rv;
54  }
55  return emsa_pss_verify(&hash[0], &enc[0], enc.size(),
56                         HASH_GetType(hash_context), mask_hash_alg,
57                         salt_len);
58}
59
60}  // namespace
61
62SignatureVerifier::SignatureVerifier()
63    : vfy_context_(NULL),
64      hash_alg_(SHA1),
65      mask_hash_alg_(SHA1),
66      salt_len_(0),
67      public_key_(NULL),
68      hash_context_(NULL) {
69  EnsureNSSInit();
70}
71
72SignatureVerifier::~SignatureVerifier() {
73  Reset();
74}
75
76bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
77                                   int signature_algorithm_len,
78                                   const uint8* signature,
79                                   int signature_len,
80                                   const uint8* public_key_info,
81                                   int public_key_info_len) {
82  if (vfy_context_ || hash_context_)
83    return false;
84
85  signature_.assign(signature, signature + signature_len);
86
87  SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info,
88                                                    public_key_info_len);
89  if (!public_key)
90    return false;
91
92  PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
93  if (!arena) {
94    SECKEY_DestroyPublicKey(public_key);
95    return false;
96  }
97
98  SECItem sig_alg_der;
99  sig_alg_der.type = siBuffer;
100  sig_alg_der.data = const_cast<uint8*>(signature_algorithm);
101  sig_alg_der.len = signature_algorithm_len;
102  SECAlgorithmID sig_alg_id;
103  SECStatus rv;
104  rv = SEC_QuickDERDecodeItem(arena, &sig_alg_id,
105                              SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
106                              &sig_alg_der);
107  if (rv != SECSuccess) {
108    SECKEY_DestroyPublicKey(public_key);
109    PORT_FreeArena(arena, PR_TRUE);
110    return false;
111  }
112
113  SECItem sig;
114  sig.type = siBuffer;
115  sig.data = const_cast<uint8*>(signature);
116  sig.len = signature_len;
117  SECOidTag hash_alg_tag;
118  vfy_context_ = VFY_CreateContextWithAlgorithmID(public_key, &sig,
119                                                  &sig_alg_id, &hash_alg_tag,
120                                                  NULL);
121  SECKEY_DestroyPublicKey(public_key);  // Done with public_key.
122  PORT_FreeArena(arena, PR_TRUE);  // Done with sig_alg_id.
123  if (!vfy_context_) {
124    // A corrupted RSA signature could be detected without the data, so
125    // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE
126    // (-8182).
127    return false;
128  }
129
130  rv = VFY_Begin(vfy_context_);
131  if (rv != SECSuccess) {
132    NOTREACHED();
133    return false;
134  }
135  return true;
136}
137
138bool SignatureVerifier::VerifyInitRSAPSS(HashAlgorithm hash_alg,
139                                         HashAlgorithm mask_hash_alg,
140                                         int salt_len,
141                                         const uint8* signature,
142                                         int signature_len,
143                                         const uint8* public_key_info,
144                                         int public_key_info_len) {
145  if (vfy_context_ || hash_context_)
146    return false;
147
148  signature_.assign(signature, signature + signature_len);
149
150  SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info,
151                                                    public_key_info_len);
152  if (!public_key)
153    return false;
154
155  public_key_ = public_key;
156  hash_alg_ = hash_alg;
157  mask_hash_alg_ = mask_hash_alg;
158  salt_len_ = salt_len;
159  hash_context_ = HASH_Create(ToNSSHashType(hash_alg_));
160  if (!hash_context_)
161    return false;
162  HASH_Begin(hash_context_);
163  return true;
164}
165
166void SignatureVerifier::VerifyUpdate(const uint8* data_part,
167                                     int data_part_len) {
168  if (vfy_context_) {
169    SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len);
170    DCHECK_EQ(SECSuccess, rv);
171  } else {
172    HASH_Update(hash_context_, data_part, data_part_len);
173  }
174}
175
176bool SignatureVerifier::VerifyFinal() {
177  SECStatus rv;
178  if (vfy_context_) {
179    rv = VFY_End(vfy_context_);
180  } else {
181    rv = VerifyRSAPSS_End(public_key_, hash_context_,
182                          ToNSSHashType(mask_hash_alg_), salt_len_,
183                          signature_.data(),
184                          signature_.size());
185  }
186  Reset();
187
188  // If signature verification fails, the error code is
189  // SEC_ERROR_BAD_SIGNATURE (-8182).
190  return (rv == SECSuccess);
191}
192
193// static
194SECKEYPublicKey* SignatureVerifier::DecodePublicKeyInfo(
195    const uint8* public_key_info,
196    int public_key_info_len) {
197  CERTSubjectPublicKeyInfo* spki = NULL;
198  SECItem spki_der;
199  spki_der.type = siBuffer;
200  spki_der.data = const_cast<uint8*>(public_key_info);
201  spki_der.len = public_key_info_len;
202  spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der);
203  if (!spki)
204    return NULL;
205  SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
206  SECKEY_DestroySubjectPublicKeyInfo(spki);  // Done with spki.
207  return public_key;
208}
209
210void SignatureVerifier::Reset() {
211  if (vfy_context_) {
212    VFY_DestroyContext(vfy_context_, PR_TRUE);
213    vfy_context_ = NULL;
214  }
215  if (hash_context_) {
216    HASH_Destroy(hash_context_);
217    hash_context_ = NULL;
218  }
219  if (public_key_) {
220    SECKEY_DestroyPublicKey(public_key_);
221    public_key_ = NULL;
222  }
223  signature_.clear();
224}
225
226}  // namespace crypto
227