1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/cert/ct_log_verifier.h"
#include <cryptohi.h>
#include <keyhi.h>
#include <nss.h>
#include <pk11pub.h>
#include <secitem.h>
#include <secoid.h>
#include "base/logging.h"
#include "crypto/nss_util.h"
#include "crypto/sha2.h"
#include "net/cert/signed_tree_head.h"
namespace net {
namespace {
SECOidTag GetNSSSigAlg(ct::DigitallySigned::SignatureAlgorithm alg) {
switch (alg) {
case ct::DigitallySigned::SIG_ALGO_RSA:
return SEC_OID_PKCS1_RSA_ENCRYPTION;
case ct::DigitallySigned::SIG_ALGO_DSA:
return SEC_OID_ANSIX9_DSA_SIGNATURE;
case ct::DigitallySigned::SIG_ALGO_ECDSA:
return SEC_OID_ANSIX962_EC_PUBLIC_KEY;
case ct::DigitallySigned::SIG_ALGO_ANONYMOUS:
default:
NOTREACHED();
return SEC_OID_UNKNOWN;
}
}
SECOidTag GetNSSHashAlg(ct::DigitallySigned::HashAlgorithm alg) {
switch (alg) {
case ct::DigitallySigned::HASH_ALGO_MD5:
return SEC_OID_MD5;
case ct::DigitallySigned::HASH_ALGO_SHA1:
return SEC_OID_SHA1;
case ct::DigitallySigned::HASH_ALGO_SHA224:
return SEC_OID_SHA224;
case ct::DigitallySigned::HASH_ALGO_SHA256:
return SEC_OID_SHA256;
case ct::DigitallySigned::HASH_ALGO_SHA384:
return SEC_OID_SHA384;
case ct::DigitallySigned::HASH_ALGO_SHA512:
return SEC_OID_SHA512;
case ct::DigitallySigned::HASH_ALGO_NONE:
default:
NOTREACHED();
return SEC_OID_UNKNOWN;
}
}
} // namespace
CTLogVerifier::~CTLogVerifier() {
if (public_key_)
SECKEY_DestroyPublicKey(public_key_);
}
CTLogVerifier::CTLogVerifier()
: hash_algorithm_(ct::DigitallySigned::HASH_ALGO_NONE),
signature_algorithm_(ct::DigitallySigned::SIG_ALGO_ANONYMOUS),
public_key_(NULL) {}
bool CTLogVerifier::Init(const base::StringPiece& public_key,
const base::StringPiece& description) {
SECItem key_data;
crypto::EnsureNSSInit();
key_data.data = reinterpret_cast<unsigned char*>(
const_cast<char*>(public_key.data()));
key_data.len = public_key.size();
CERTSubjectPublicKeyInfo* public_key_info =
SECKEY_DecodeDERSubjectPublicKeyInfo(&key_data);
if (!public_key_info) {
DVLOG(1) << "Failed decoding public key.";
return false;
}
public_key_ = SECKEY_ExtractPublicKey(public_key_info);
SECKEY_DestroySubjectPublicKeyInfo(public_key_info);
if (!public_key_) {
DVLOG(1) << "Failed extracting public key.";
return false;
}
key_id_ = crypto::SHA256HashString(public_key);
description_ = description.as_string();
// Right now, only RSASSA-PKCS1v15 with SHA-256 and ECDSA with SHA-256 are
// supported.
switch (SECKEY_GetPublicKeyType(public_key_)) {
case rsaKey:
hash_algorithm_ = ct::DigitallySigned::HASH_ALGO_SHA256;
signature_algorithm_ = ct::DigitallySigned::SIG_ALGO_RSA;
break;
case ecKey:
hash_algorithm_ = ct::DigitallySigned::HASH_ALGO_SHA256;
signature_algorithm_ = ct::DigitallySigned::SIG_ALGO_ECDSA;
break;
default:
DVLOG(1) << "Unsupported key type: "
<< SECKEY_GetPublicKeyType(public_key_);
return false;
}
// Extra sanity check: Require RSA keys of at least 2048 bits.
if (signature_algorithm_ == ct::DigitallySigned::SIG_ALGO_RSA &&
SECKEY_PublicKeyStrengthInBits(public_key_) < 2048) {
DVLOG(1) << "Too small a public key.";
return false;
}
return true;
}
bool CTLogVerifier::VerifySignature(const base::StringPiece& data_to_sign,
const base::StringPiece& signature) {
SECItem sig_data;
sig_data.data = reinterpret_cast<unsigned char*>(const_cast<char*>(
signature.data()));
sig_data.len = signature.size();
SECStatus rv = VFY_VerifyDataDirect(
reinterpret_cast<const unsigned char*>(data_to_sign.data()),
data_to_sign.size(), public_key_, &sig_data,
GetNSSSigAlg(signature_algorithm_), GetNSSHashAlg(hash_algorithm_),
NULL, NULL);
DVLOG(1) << "Signature verification result: " << (rv == SECSuccess);
return rv == SECSuccess;
}
} // namespace net
|