Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: net/cert/internal/signature_algorithm.cc

Issue 1218753002: Add DER parsing of AlgorithmId for signatures. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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 "net/cert/internal/signature_algorithm.h"
6
7 #include <stdint.h>
8
9 #include "net/der/input.h"
10 #include "net/der/parser.h"
11
12 namespace net {
13
14 namespace {
15
16 // From RFC 3279 section 2.2.1:
17 // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= {
18 // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
19 // pkcs-1(1) 5 }
20 // In dotted notation: 1.2.840.113549.1.1.5
21 const uint8_t kOidSha1WithRsaEncryption[] =
22 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05};
23
24 // From RFC 4055 section 6:
25 // pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
26 // us(840) rsadsi(113549) pkcs(1) 1 }
27
28 // From RFC 4055 section 5:
29 // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
30 // In dotted notation: 1.2.840.113549.1.1.11
31 const uint8_t kOidSha256WithRsaEncryption[] =
32 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b};
33
34 // From RFC 4055 section 5:
35 // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
36 // In dotted notation: 1.2.840.113549.1.1.12
37 const uint8_t kOidSha384WithRsaEncryption[] =
38 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c};
39
40 // From RFC 4055 section 5:
41 // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
42 // In dotted notation: 1.2.840.113549.1.1.13
43 const uint8_t kOidSha512WithRsaEncryption[] =
44 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d};
45
46 // From RFC 3279 section 2.2.3:
47 // ansi-X9-62 OBJECT IDENTIFIER ::= {
48 // iso(1) member-body(2) us(840) 10045 }
49 //
50 // id-ecSigType OBJECT IDENTIFIER ::= {
51 // ansi-X9-62 signatures(4) }
52 //
53 // ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
54 // id-ecSigType 1 }
55 // In dotted notation: 1.2.840.10045.4.1
56 const uint8_t kOidEcdsaWithSha1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01};
57
58 // From RFC 5758 section 3.2:
59 // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
60 // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
61 // In dotted notation: 1.2.840.10045.4.3.2
62 const uint8_t kOidEcdsaWithSha256[] =
63 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02};
64
65 // From RFC 5758 section 3.2:
66 // ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
67 // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 }
68 // In dotted notation: 1.2.840.10045.4.3.3
69 const uint8_t kOidEcdsaWithSha384[] =
70 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03};
71
72 // From RFC 5758 section 3.2:
73 // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
74 // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 }
75 // In dotted notation: 1.2.840.10045.4.3.4
76 const uint8_t kOidEcdsaWithSha512[] =
77 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04};
78
79 // From RFC 4055 section 3.1:
80 // id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 }
81 // In dotted notation: 1.2.840.113549.1.1.10
82 const uint8_t kOidRsaSsaPss[] =
83 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a};
84
85 // RFC 5280 section 4.1.1.2 defines signatureAlgorithm as:
86 //
87 // AlgorithmIdentifier ::= SEQUENCE {
88 // algorithm OBJECT IDENTIFIER,
89 // parameters ANY DEFINED BY algorithm OPTIONAL }
90 WARN_UNUSED_RESULT bool ParseAlgorithmIdentifier(const der::Input& input,
91 der::Input* algorithm,
92 der::Input* parameters) {
93 der::Parser parser(input);
94
95 der::Parser algorithm_identifier_parser;
96 if (!parser.ReadSequence(&algorithm_identifier_parser))
97 return false;
98
99 // There shouldn't be anything after the sequence.
100 if (parser.HasMore())
101 return false;
102
103 if (!algorithm_identifier_parser.ReadTag(der::kOid, algorithm))
104 return false;
105
106 // Read the optional parameters to a der::Input. The parameters can be at
107 // most one TLV (for instance NULL or a sequence).
108 *parameters = der::Input();
109 if (algorithm_identifier_parser.HasMore() &&
110 !algorithm_identifier_parser.ReadRawTLV(parameters)) {
111 return false;
112 }
113 return !algorithm_identifier_parser.HasMore();
Ryan Sleevi 2015/07/07 13:55:15 It's perfectly fine for an algorithm to have addit
eroman 2015/07/08 01:09:34 For anyone following, this is the same conversatio
Ryan Sleevi 2015/07/08 11:44:01 The result being that as a result if we adopt the
eroman 2015/07/14 20:31:38 I have added comments to each place in the code th
114 }
115
116 // Returns true if the entirety of the input is a NULL value, or is empty.
117 WARN_UNUSED_RESULT bool IsNullOrEmpty(const der::Input& input) {
118 if (input.Length() == 0)
119 return true;
120
121 der::Parser parser(input);
122 der::Input null_value;
123 if (!parser.ReadTag(der::kNull, &null_value))
124 return false;
125
126 // NULL values are TLV encoded; the value is expected to be empty.
127 if (null_value.Length() != 0)
128 return false;
129
130 return !parser.HasMore();
131 }
132
133 // Parses parameters for RSA PKCS#1 v1.5 from |parameters_parser| (ensure there
134 // are none), and assigns the resulting algorithm identifier to |*out|.
135 //
136 // Returns true on success.
137 //
138 // Note that the parameter parsing used is more permissive than the specs with
139 // regards to sha-1WithRSAEncryption - it accepts both NULL and empty
140 // parameters.
141 //
142 // Relevant specs:
143 //
144 // RFC 4055 section 5 (in reference to sha256WithRSAEncryption et al):
145 // When any of these four object identifiers appears within an
146 // AlgorithmIdentifier, the parameters MUST be NULL. Implementations
147 // MUST accept the parameters being absent as well as present.
148 //
149 // RFC 3279 section 2.2.1 (in reference to sha-1WithRSAEncryption):
150 // When any of these three OIDs appears within the ASN.1 type
151 // AlgorithmIdentifier, the parameters component of that type SHALL be
152 // the ASN.1 type NULL.
153 WARN_UNUSED_RESULT bool ParseRsaPkcs1(DigestAlgorithm digest,
154 const der::Input& params,
155 SignatureAlgorithm* out) {
156 if (!IsNullOrEmpty(params))
157 return false;
158
159 out->AssignRsaPkcs1(digest);
160 return true;
161 }
162
163 // Parses parameters for ECDSA from |parameters_parser| (ensure there
164 // are none), and assigns the resulting algorithm identifier to |*out|.
165 //
166 // Returns true on success.
167 //
168 // Note that the parameter parsing used is more permissive than the specs with
169 // regards - it additionally accepts NULL parameters.
Ryan Sleevi 2015/07/07 13:55:15 Why?
eroman 2015/07/08 01:09:34 Isn't this a moot point based on your earlier comm
Ryan Sleevi 2015/07/08 11:44:01 So if we're adopting the 5912 rules (as discussed
eroman 2015/07/14 20:31:38 I have re-written most of the RFC references in te
170 //
171 // Relevant specs:
172 //
173 // RFC 5758 section-3.2:
174 // When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
175 // ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
176 // as an AlgorithmIdentifier, the encoding MUST omit the parameters
177 // field. That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
178 // component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
179 // SHA384, or ecdsa-with-SHA512.
180 //
181 // RFC 3279 section 2.2.3:
182 // When the ecdsa-with-SHA1 algorithm identifier appears as the
183 // algorithm field in an AlgorithmIdentifier, the encoding MUST omit the
184 // parameters field. That is, the AlgorithmIdentifier SHALL be a
185 // SEQUENCE of one component: the OBJECT IDENTIFIER ecdsa-with-SHA1.
186 WARN_UNUSED_RESULT bool ParseEcdsa(DigestAlgorithm digest,
187 const der::Input& params,
188 SignatureAlgorithm* out) {
189 if (!IsNullOrEmpty(params))
190 return false;
191
192 out->AssignEcdsa(digest);
193 return true;
194 }
195
196 // From RFC 4055:
197 // RSASSA-PSS-params ::= SEQUENCE {
198 // hashAlgorithm [0] HashAlgorithm DEFAULT
199 // sha1Identifier,
200 // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT
201 // mgf1SHA1Identifier,
202 // saltLength [2] INTEGER DEFAULT 20,
203 // trailerField [3] INTEGER DEFAULT 1 }
204 //
205 // HashAlgorithm ::= AlgorithmIdentifier
206 //
207 // MaskGenAlgorithm ::= AlgorithmIdentifier
208 WARN_UNUSED_RESULT bool ParseRsaPss(const der::Input& params,
209 SignatureAlgorithm* out) {
210 // TODO(eroman): Implement.
211 return false;
212 }
213
214 } // namespace
215
216 RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash,
217 uint32_t salt_length)
218 : mgf1_hash_(mgf1_hash), salt_length_(salt_length) {
219 }
220
221 bool RsaPssParameters::Equals(const SignatureAlgorithmParameters* other) const {
222 const RsaPssParameters* params = static_cast<const RsaPssParameters*>(other);
223 return mgf1_hash_ == params->mgf1_hash_ &&
224 salt_length_ == params->salt_length_;
225 }
226
227 SignatureAlgorithm::SignatureAlgorithm() {
228 AssignInvalid();
229 }
230
231 SignatureAlgorithm::~SignatureAlgorithm() {
232 }
233
234 bool SignatureAlgorithm::IsValid() const {
235 return params_;
236 }
237
238 SignatureAlgorithmId SignatureAlgorithm::algorithm() const {
239 DCHECK(IsValid());
240 return algorithm_;
241 }
242
243 DigestAlgorithm SignatureAlgorithm::digest() const {
244 DCHECK(IsValid());
245 return digest_;
246 }
247
248 bool SignatureAlgorithm::ParseDer(const der::Input& algorithm_identifier) {
249 AssignInvalid();
250
251 der::Input oid;
252 der::Input params;
253 if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, &params))
254 return false;
255
256 // TODO(eroman): Each OID is tested for equality in order, which is not
257 // particularly efficient.
258
259 if (oid.Equals(der::Input(kOidSha1WithRsaEncryption)))
260 return ParseRsaPkcs1(DigestAlgorithm::Sha1, params, this);
261
262 if (oid.Equals(der::Input(kOidSha256WithRsaEncryption)))
263 return ParseRsaPkcs1(DigestAlgorithm::Sha256, params, this);
264
265 if (oid.Equals(der::Input(kOidSha384WithRsaEncryption)))
266 return ParseRsaPkcs1(DigestAlgorithm::Sha384, params, this);
267
268 if (oid.Equals(der::Input(kOidSha512WithRsaEncryption)))
269 return ParseRsaPkcs1(DigestAlgorithm::Sha512, params, this);
270
271 if (oid.Equals(der::Input(kOidEcdsaWithSha1)))
272 return ParseEcdsa(DigestAlgorithm::Sha1, params, this);
273
274 if (oid.Equals(der::Input(kOidEcdsaWithSha256)))
275 return ParseEcdsa(DigestAlgorithm::Sha256, params, this);
276
277 if (oid.Equals(der::Input(kOidEcdsaWithSha384)))
278 return ParseEcdsa(DigestAlgorithm::Sha384, params, this);
279
280 if (oid.Equals(der::Input(kOidEcdsaWithSha512)))
281 return ParseEcdsa(DigestAlgorithm::Sha512, params, this);
282
283 if (oid.Equals(der::Input(kOidRsaSsaPss)))
284 return ParseRsaPss(params, this);
285
286 return false; // Unsupported OID.
287 }
288
289 void SignatureAlgorithm::AssignRsaPkcs1(DigestAlgorithm digest) {
290 algorithm_ = SignatureAlgorithmId::RsaPkcs1;
291 digest_ = digest;
292 params_.reset();
293 }
294
295 void SignatureAlgorithm::AssignEcdsa(DigestAlgorithm digest) {
296 algorithm_ = SignatureAlgorithmId::Ecdsa;
297 digest_ = digest;
298 params_.reset();
299 }
300
301 void SignatureAlgorithm::AssignRsaPss(DigestAlgorithm digest,
302 DigestAlgorithm mgf1_hash,
303 uint32_t salt_length) {
304 algorithm_ = SignatureAlgorithmId::RsaPss;
305 digest_ = digest;
306 params_.reset(new RsaPssParameters(mgf1_hash, salt_length));
307 }
308
309 bool SignatureAlgorithm::Equals(const SignatureAlgorithm& other) const {
310 if (algorithm_ != other.algorithm_)
311 return false;
312
313 if (digest_ != other.digest_)
314 return false;
315
316 if (!params_ != !other.params_)
317 return false;
318
319 if (params_ && !params_->Equals(other.params_.get()))
320 return false;
321
322 return true;
323 }
324
325 const RsaPssParameters* SignatureAlgorithm::ParamsForRsaPss() const {
326 if (algorithm_ == SignatureAlgorithmId::RsaPss)
327 return static_cast<RsaPssParameters*>(params_.get());
328 return nullptr;
329 }
330
331 void SignatureAlgorithm::AssignInvalid() {
332 algorithm_ = static_cast<SignatureAlgorithmId>(-1);
333 digest_ = static_cast<DigestAlgorithm>(-1);
334 params_.reset();
335 }
336
337 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698