Index: net/base/asn1_util.cc |
diff --git a/net/base/asn1_util.cc b/net/base/asn1_util.cc |
index ee25d41be8cb22cb58aca4e406c34b3485f24029..a1e8637f8706a95f0aacdc8ad295e6f785322952 100644 |
--- a/net/base/asn1_util.cc |
+++ b/net/base/asn1_util.cc |
@@ -14,11 +14,32 @@ bool ParseElement(base::StringPiece* in, |
unsigned *out_header_len) { |
const uint8* data = reinterpret_cast<const uint8*>(in->data()); |
+ // We don't support kAny and kOptional at the same time. |
+ if ((tag_value & kAny) && (tag_value & kOptional)) |
+ return false; |
+ |
+ if (in->empty() && (tag_value & kOptional)) { |
+ if (out_header_len) |
+ *out_header_len = 0; |
+ if (out) |
+ *out = base::StringPiece(); |
+ return true; |
+ } |
+ |
if (in->size() < 2) |
return false; |
- if (tag_value != kAny && static_cast<unsigned char>(data[0]) != tag_value) |
+ if (tag_value != kAny && |
+ static_cast<unsigned char>(data[0]) != (tag_value & 0xff)) { |
+ if (tag_value & kOptional) { |
+ if (out_header_len) |
+ *out_header_len = 0; |
+ if (out) |
+ *out = base::StringPiece(); |
+ return true; |
+ } |
return false; |
+ } |
size_t len = 0; |
if ((data[1] & 0x80) == 0) { |
@@ -71,9 +92,9 @@ bool GetElement(base::StringPiece* in, |
return true; |
} |
-// SeekToSPKI changes |cert| so that it points to a suffix of the original |
-// value where the suffix begins at the start of the ASN.1 SubjectPublicKeyInfo |
-// value. |
+// SeekToSPKI changes |cert| so that it points to a suffix of the |
+// TBSCertificate where the suffix begins at the start of the ASN.1 |
+// SubjectPublicKeyInfo value. |
static bool SeekToSPKI(base::StringPiece* cert) { |
// From RFC 5280, section 4.1 |
// Certificate ::= SEQUENCE { |
@@ -94,14 +115,19 @@ static bool SeekToSPKI(base::StringPiece* cert) { |
if (!GetElement(cert, kSEQUENCE, &certificate)) |
return false; |
+ // We don't allow junk after the certificate. |
+ if (!cert->empty()) |
+ return false; |
+ |
base::StringPiece tbs_certificate; |
if (!GetElement(&certificate, kSEQUENCE, &tbs_certificate)) |
return false; |
- // The version is optional, so a failure to parse it is fine. |
- GetElement(&tbs_certificate, |
- kCompound | kContextSpecific | 0, |
- NULL); |
+ if (!GetElement(&tbs_certificate, |
+ kOptional | kConstructed | kContextSpecific | 0, |
+ NULL)) { |
+ return false; |
+ } |
// serialNumber |
if (!GetElement(&tbs_certificate, kINTEGER, NULL)) |
@@ -134,6 +160,7 @@ bool ExtractSPKIFromDERCert(base::StringPiece cert, |
bool ExtractCRLURLsFromDERCert(base::StringPiece cert, |
std::vector<base::StringPiece>* urls_out) { |
urls_out->clear(); |
+ std::vector<base::StringPiece> tmp_urls_out; |
if (!SeekToSPKI(&cert)) |
return false; |
@@ -150,17 +177,21 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert, |
if (!GetElement(&cert, kSEQUENCE, NULL)) |
return false; |
// issuerUniqueID |
- GetElement(&cert, kCompound | kContextSpecific | 1, NULL); |
+ if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 1, NULL)) |
+ return false; |
// subjectUniqueID |
- GetElement(&cert, kCompound | kContextSpecific | 2, NULL); |
+ if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 2, NULL)) |
+ return false; |
base::StringPiece extensions_seq; |
- if (!GetElement(&cert, kCompound | kContextSpecific | 3, |
+ if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 3, |
&extensions_seq)) { |
- // If there are no extensions, then there are no CRL URLs. |
- return true; |
+ return false; |
} |
+ if (extensions_seq.empty()) |
+ return true; |
+ |
// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension |
// Extension ::= SEQUENCE { |
// extnID OBJECT IDENTIFIER, |
@@ -218,7 +249,7 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert, |
return false; |
base::StringPiece name; |
- if (!GetElement(&distrib_point, kContextSpecific | kCompound | 0, |
+ if (!GetElement(&distrib_point, kContextSpecific | kConstructed | 0, |
&name)) { |
// If it doesn't contain a name then we skip it. |
continue; |
@@ -231,7 +262,8 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert, |
continue; |
} |
- if (GetElement(&distrib_point, kContextSpecific | kCompound | 2, NULL)) { |
+ if (GetElement(&distrib_point, |
+ kContextSpecific | kConstructed | 2, NULL)) { |
// If it contains a alternative issuer, then we skip it. |
continue; |
} |
@@ -240,8 +272,10 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert, |
// fullName [0] GeneralNames, |
// nameRelativeToCRLIssuer [1] RelativeDistinguishedName } |
base::StringPiece general_names; |
- if (!GetElement(&name, kContextSpecific | kCompound | 0, &general_names)) |
+ if (!GetElement(&name, |
+ kContextSpecific | kConstructed | 0, &general_names)) { |
continue; |
+ } |
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName |
// GeneralName ::= CHOICE { |
@@ -251,7 +285,7 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert, |
while (general_names.size() > 0) { |
base::StringPiece url; |
if (GetElement(&general_names, kContextSpecific | 6, &url)) { |
- urls_out->push_back(url); |
+ tmp_urls_out.push_back(url); |
} else { |
if (!GetElement(&general_names, kAny, NULL)) |
return false; |
@@ -260,6 +294,7 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert, |
} |
} |
+ urls_out->swap(tmp_urls_out); |
return true; |
} |