- add sources.
[platform/framework/web/crosswalk.git] / src / crypto / signature_verifier_nss.cc
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
18 namespace crypto {
19
20 namespace {
21
22 HASH_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
32 SECStatus 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
62 SignatureVerifier::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
72 SignatureVerifier::~SignatureVerifier() {
73   Reset();
74 }
75
76 bool 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
138 bool 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
166 void 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
176 bool 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
194 SECKEYPublicKey* 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
210 void 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