OLD | NEW |
---|---|
(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, ¶ms)) | |
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 | |
OLD | NEW |