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

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

Issue 1125333005: RFC 2459 name comparison. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 5 years, 7 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
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
OLDNEW
« no previous file with comments | « no previous file | net/cert/internal/verify_name_match_unittest.cc » ('j') | net/cert/internal/verify_name_match_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698