OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/strings/string_util.h" | |
5 #include "net/cert/internal/verify_name_match.h" | 6 #include "net/cert/internal/verify_name_match.h" |
6 #include "net/der/input.h" | 7 #include "net/der/input.h" |
8 #include "net/der/parser.h" | |
9 #include "net/der/tag.h" | |
7 | 10 |
8 namespace net { | 11 namespace net { |
9 | 12 |
13 namespace { | |
14 | |
15 class PrintableStringNormalizer { | |
Ryan Sleevi
2015/05/13 01:27:52
Document :)
mattm
2015/05/13 03:24:05
Acknowledged.
| |
16 public: | |
17 explicit PrintableStringNormalizer(const der::Input& in) | |
18 : reader_(in), in_begin_(true) {} | |
19 | |
20 bool ReadByte(uint8_t* out) { | |
Ryan Sleevi
2015/05/13 01:27:52
Because these are non-trivial, my suggestion would
mattm
2015/05/13 03:24:05
Acknowledged.
| |
21 if (in_begin_) { | |
22 // Ignore leading whitespace. | |
23 SkipWhitespace(); | |
24 in_begin_ = false; | |
25 } | |
26 | |
27 uint8_t c; | |
28 if (!reader_.ReadByte(&c)) | |
29 return false; | |
30 | |
31 if (c == ' ') { | |
32 if (SkipWhitespace()) { | |
33 // If there is non-whitespace characters remaining in input, compress | |
34 // multiple whitespace chars to a single space. | |
35 *out = c; | |
36 return true; | |
37 } else { | |
38 // If there is trailing whitespace, ignore it. | |
39 return false; | |
40 } | |
41 } | |
42 | |
43 *out = base::ToLowerASCII(c); | |
Ryan Sleevi
2015/05/13 01:27:52
So this doesn't enforce that |c| is validly encode
mattm
2015/05/13 03:24:05
Done.
| |
44 return true; | |
45 } | |
46 | |
47 private: | |
48 // Skip whitespace, if any. Return true if characters remain in input. | |
49 bool SkipWhitespace() { | |
50 der::ByteReader peaker(reader_); | |
51 while (true) { | |
52 uint8_t c; | |
53 if (!peaker.ReadByte(&c)) | |
54 return false; | |
55 if (c == ' ') { | |
56 if (!reader_.ReadByte(&c)) | |
57 NOTREACHED(); | |
58 } else { | |
59 return true; | |
60 } | |
61 } | |
62 } | |
63 | |
64 der::ByteReader reader_; | |
65 bool in_begin_; | |
66 }; | |
Ryan Sleevi
2015/05/13 01:27:52
So as a design point, this won't scale when it com
mattm
2015/05/13 03:24:05
Done.
| |
67 | |
68 // Compare two PrintableString values according to RFC 2459 section 4.1.2.4. | |
69 bool PrintableStringMatch(const der::Input& a, const der::Input& b) { | |
70 PrintableStringNormalizer a_reader(a); | |
71 PrintableStringNormalizer b_reader(b); | |
72 | |
73 while (true) { | |
74 uint8_t a_byte, b_byte; | |
75 bool a_done = !a_reader.ReadByte(&a_byte); | |
76 bool b_done = !b_reader.ReadByte(&b_byte); | |
77 | |
78 if (a_done && b_done) | |
79 return true; | |
80 | |
81 if (a_done || b_done) | |
82 return false; | |
83 | |
84 if (a_byte != b_byte) | |
85 return false; | |
Ryan Sleevi
2015/05/13 01:27:52
This ends up being pretty inefficient in a tight l
mattm
2015/05/13 03:24:05
Acknowledged.
| |
86 } | |
87 } | |
88 | |
89 bool VerifyAttributeValueMatch(der::Parser* a, der::Parser* b) { | |
90 der::Tag a_tag, b_tag; | |
91 der::Input a_value, b_value; | |
92 | |
93 // Read the attribute type. | |
94 if (!a->ReadTagAndValue(&a_tag, &a_value)) | |
95 return false; | |
96 if (!b->ReadTagAndValue(&b_tag, &b_value)) | |
97 return false; | |
98 // Type of "Attribute type" must be OBJECT IDENTIFIER. | |
99 if (a_tag != der::kOid || b_tag != der::kOid) | |
100 return false; | |
101 // Attribute types must be equal. | |
102 if (!a_value.Equals(b_value)) | |
103 return false; | |
104 | |
105 // Read the attribute value. | |
106 if (!a->ReadTagAndValue(&a_tag, &a_value)) | |
107 return false; | |
108 if (!b->ReadTagAndValue(&b_tag, &b_value)) | |
109 return false; | |
110 | |
111 // TODO(mattm): use normalization as specified in RFC 5280 section 7. | |
112 | |
113 // RFC 2459 section 4.1.2.4 comparison rules: | |
114 // Attributes encoded with different types may be assumed to be unequal. | |
115 if (a_tag != b_tag) | |
116 return false; | |
117 if (a_tag == der::kPrintableString) { | |
118 // PrintableString values should be compared case insenstive and ignoring | |
119 // extraneous whitespace. | |
120 return PrintableStringMatch(a_value, b_value); | |
121 } else { | |
122 // Types other than PrintableString use binary comparison. | |
123 return a_value.Equals(b_value); | |
124 } | |
125 } | |
126 | |
127 bool VerifyRDNMatch(der::Parser* a, der::Parser* b) { | |
128 while (a->HasMore() && b->HasMore()) { | |
129 der::Parser a_attr_type_and_value; | |
130 der::Parser b_attr_type_and_value; | |
131 if (!a->ReadSequence(&a_attr_type_and_value) || | |
132 !b->ReadSequence(&b_attr_type_and_value)) | |
133 return false; | |
134 if (!VerifyAttributeValueMatch(&a_attr_type_and_value, | |
135 &b_attr_type_and_value)) | |
136 return false; | |
137 } | |
138 | |
139 // If one of the RDNs has more elements than the other, not a match. | |
140 if (a->HasMore() || b->HasMore()) | |
141 return false; | |
142 | |
143 return true; | |
144 } | |
145 | |
146 } // namespace | |
147 | |
148 // TODO(mattm): is returning false on parsing errors ok, or should it try to | |
149 // fall back to binary comparison on unexpected input? | |
10 bool VerifyNameMatch(const der::Input& a, const der::Input& b) { | 150 bool VerifyNameMatch(const der::Input& a, const der::Input& b) { |
11 // TODO(mattm): use normalization as specified in RFC 5280 section 7. | 151 der::Parser a_parser(a); |
12 return a.Equals(b); | 152 der::Parser b_parser(b); |
153 der::Parser a_rdn_sequence; | |
154 der::Parser b_rdn_sequence; | |
155 | |
156 if (!a_parser.ReadSequence(&a_rdn_sequence) || | |
157 !b_parser.ReadSequence(&b_rdn_sequence)) | |
158 return false; | |
Ryan Sleevi
2015/05/13 01:27:52
braces
mattm
2015/05/13 03:24:05
Done.
| |
159 | |
160 while (a_rdn_sequence.HasMore() && b_rdn_sequence.HasMore()) { | |
161 der::Parser a_rdn, b_rdn; | |
162 if (!a_rdn_sequence.ReadConstructed(der::kSet, &a_rdn) || | |
163 !b_rdn_sequence.ReadConstructed(der::kSet, &b_rdn)) | |
164 return false; | |
Ryan Sleevi
2015/05/13 01:27:52
braces
mattm
2015/05/13 03:24:06
Done.
| |
165 if (!VerifyRDNMatch(&a_rdn, &b_rdn)) | |
166 return false; | |
167 } | |
168 | |
169 // If one of the sequences has more elements than the other, not a match. | |
170 if (a_rdn_sequence.HasMore() || b_rdn_sequence.HasMore()) | |
171 return false; | |
172 | |
173 return true; | |
13 } | 174 } |
14 | 175 |
15 } // namespace net | 176 } // namespace net |
OLD | NEW |