1 // Copyright (c) 2008 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/hmac.h"
6
7 #include <nss.h>
8 #include <pk11pub.h>
9
10 #include "base/logging.h"
11 #include "base/nss_util.h"
12 #include "base/scoped_ptr.h"
13
14 namespace {
15
16 template <typename Type, void (*Destroyer)(Type*)>
17 struct NSSDestroyer {
operator ()__anon982e36f80111::NSSDestroyer18 void operator()(Type* ptr) const {
19 if (ptr)
20 Destroyer(ptr);
21 }
22 };
23
DestroyContext(PK11Context * context)24 void DestroyContext(PK11Context* context) {
25 PK11_DestroyContext(context, PR_TRUE);
26 }
27
28 // Define some convenient scopers around NSS pointers.
29 typedef scoped_ptr_malloc<
30 PK11SlotInfo, NSSDestroyer<PK11SlotInfo, PK11_FreeSlot> > ScopedNSSSlot;
31 typedef scoped_ptr_malloc<
32 PK11SymKey, NSSDestroyer<PK11SymKey, PK11_FreeSymKey> > ScopedNSSSymKey;
33 typedef scoped_ptr_malloc<
34 PK11Context, NSSDestroyer<PK11Context, DestroyContext> > ScopedNSSContext;
35
36 } // namespace
37
38 namespace base {
39
40 struct HMACPlatformData {
41 ScopedNSSSlot slot_;
42 ScopedNSSSymKey sym_key_;
43 };
44
HMAC(HashAlgorithm hash_alg)45 HMAC::HMAC(HashAlgorithm hash_alg)
46 : hash_alg_(hash_alg), plat_(new HMACPlatformData()) {
47 // Only SHA-1 digest is supported now.
48 DCHECK(hash_alg_ == SHA1);
49 }
50
Init(const unsigned char * key,int key_length)51 bool HMAC::Init(const unsigned char *key, int key_length) {
52 base::EnsureNSSInit();
53
54 if (hash_alg_ != SHA1) {
55 NOTREACHED();
56 return false;
57 }
58
59 if (plat_->slot_.get()) {
60 // Init must not be called more than twice on the same HMAC object.
61 NOTREACHED();
62 return false;
63 }
64
65 plat_->slot_.reset(PK11_GetBestSlot(CKM_SHA_1_HMAC, NULL));
66 if (!plat_->slot_.get()) {
67 NOTREACHED();
68 return false;
69 }
70
71 SECItem key_item;
72 key_item.type = siBuffer;
73 key_item.data = const_cast<unsigned char*>(key); // NSS API isn't const.
74 key_item.len = key_length;
75
76 plat_->sym_key_.reset(PK11_ImportSymKey(plat_->slot_.get(),
77 CKM_SHA_1_HMAC,
78 PK11_OriginUnwrap,
79 CKA_SIGN,
80 &key_item,
81 NULL));
82 if (!plat_->sym_key_.get()) {
83 NOTREACHED();
84 return false;
85 }
86
87 return true;
88 }
89
~HMAC()90 HMAC::~HMAC() {
91 }
92
Sign(const std::string & data,unsigned char * digest,int digest_length)93 bool HMAC::Sign(const std::string& data,
94 unsigned char* digest,
95 int digest_length) {
96 if (!plat_->sym_key_.get()) {
97 // Init has not been called before Sign.
98 NOTREACHED();
99 return false;
100 }
101
102 SECItem param = { siBuffer, NULL, 0 };
103 ScopedNSSContext context(PK11_CreateContextBySymKey(CKM_SHA_1_HMAC,
104 CKA_SIGN,
105 plat_->sym_key_.get(),
106 ¶m));
107 if (!context.get()) {
108 NOTREACHED();
109 return false;
110 }
111
112 if (PK11_DigestBegin(context.get()) != SECSuccess) {
113 NOTREACHED();
114 return false;
115 }
116
117 if (PK11_DigestOp(context.get(),
118 reinterpret_cast<const unsigned char*>(data.data()),
119 data.length()) != SECSuccess) {
120 NOTREACHED();
121 return false;
122 }
123
124 unsigned int len = 0;
125 if (PK11_DigestFinal(context.get(),
126 digest, &len, digest_length) != SECSuccess) {
127 NOTREACHED();
128 return false;
129 }
130
131 return true;
132 }
133
134 } // namespace base
135