• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2009 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 "base/crypto/signature_verifier.h"
6 
7 #include <cryptohi.h>
8 #include <keyhi.h>
9 #include <stdlib.h>
10 
11 #include "base/logging.h"
12 #include "base/nss_util.h"
13 
14 namespace base {
15 
SignatureVerifier()16 SignatureVerifier::SignatureVerifier() : vfy_context_(NULL) {
17   EnsureNSSInit();
18 }
19 
~SignatureVerifier()20 SignatureVerifier::~SignatureVerifier() {
21   Reset();
22 }
23 
VerifyInit(const uint8 * signature_algorithm,int signature_algorithm_len,const uint8 * signature,int signature_len,const uint8 * public_key_info,int public_key_info_len)24 bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
25                                    int signature_algorithm_len,
26                                    const uint8* signature,
27                                    int signature_len,
28                                    const uint8* public_key_info,
29                                    int public_key_info_len) {
30   signature_.assign(signature, signature + signature_len);
31 
32   CERTSubjectPublicKeyInfo* spki = NULL;
33   SECItem spki_der;
34   spki_der.type = siBuffer;
35   spki_der.data = const_cast<uint8*>(public_key_info);
36   spki_der.len = public_key_info_len;
37   spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der);
38   if (!spki)
39     return false;
40   SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
41   SECKEY_DestroySubjectPublicKeyInfo(spki);  // Done with spki.
42   if (!public_key)
43     return false;
44 
45   PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
46   if (!arena) {
47     SECKEY_DestroyPublicKey(public_key);
48     return false;
49   }
50 
51   SECItem sig_alg_der;
52   sig_alg_der.type = siBuffer;
53   sig_alg_der.data = const_cast<uint8*>(signature_algorithm);
54   sig_alg_der.len = signature_algorithm_len;
55   SECAlgorithmID sig_alg_id;
56   SECStatus rv;
57   rv = SEC_QuickDERDecodeItem(arena, &sig_alg_id, SECOID_AlgorithmIDTemplate,
58                               &sig_alg_der);
59   if (rv != SECSuccess) {
60     SECKEY_DestroyPublicKey(public_key);
61     PORT_FreeArena(arena, PR_TRUE);
62     return false;
63   }
64 
65   SECItem sig;
66   sig.type = siBuffer;
67   sig.data = const_cast<uint8*>(signature);
68   sig.len = signature_len;
69   SECOidTag hash_alg_tag;
70   vfy_context_ = VFY_CreateContextWithAlgorithmID(public_key, &sig,
71                                                   &sig_alg_id, &hash_alg_tag,
72                                                   NULL);
73   SECKEY_DestroyPublicKey(public_key);  // Done with public_key.
74   PORT_FreeArena(arena, PR_TRUE);  // Done with sig_alg_id.
75   if (!vfy_context_) {
76     // A corrupted RSA signature could be detected without the data, so
77     // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE
78     // (-8182).
79     return false;
80   }
81 
82   rv = VFY_Begin(vfy_context_);
83   if (rv != SECSuccess) {
84     NOTREACHED();
85     return false;
86   }
87   return true;
88 }
89 
VerifyUpdate(const uint8 * data_part,int data_part_len)90 void SignatureVerifier::VerifyUpdate(const uint8* data_part,
91                                      int data_part_len) {
92   SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len);
93   DCHECK(rv == SECSuccess);
94 }
95 
VerifyFinal()96 bool SignatureVerifier::VerifyFinal() {
97   SECStatus rv = VFY_End(vfy_context_);
98   Reset();
99 
100   // If signature verification fails, the error code is
101   // SEC_ERROR_BAD_SIGNATURE (-8182).
102   return (rv == SECSuccess);
103 }
104 
Reset()105 void SignatureVerifier::Reset() {
106   if (vfy_context_) {
107     VFY_DestroyContext(vfy_context_, PR_TRUE);
108     vfy_context_ = NULL;
109   }
110   signature_.clear();
111 }
112 
113 }  // namespace base
114