| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/base/asn1_util.h" | |
| 6 | |
| 7 namespace net { | |
| 8 | |
| 9 namespace asn1 { | |
| 10 | |
| 11 bool ParseElement(base::StringPiece* in, | |
| 12 unsigned tag_value, | |
| 13 base::StringPiece* out, | |
| 14 unsigned *out_header_len) { | |
| 15 const uint8* data = reinterpret_cast<const uint8*>(in->data()); | |
| 16 | |
| 17 // We don't support kAny and kOptional at the same time. | |
| 18 if ((tag_value & kAny) && (tag_value & kOptional)) | |
| 19 return false; | |
| 20 | |
| 21 if (in->empty() && (tag_value & kOptional)) { | |
| 22 if (out_header_len) | |
| 23 *out_header_len = 0; | |
| 24 if (out) | |
| 25 *out = base::StringPiece(); | |
| 26 return true; | |
| 27 } | |
| 28 | |
| 29 if (in->size() < 2) | |
| 30 return false; | |
| 31 | |
| 32 if (tag_value != kAny && | |
| 33 static_cast<unsigned char>(data[0]) != (tag_value & 0xff)) { | |
| 34 if (tag_value & kOptional) { | |
| 35 if (out_header_len) | |
| 36 *out_header_len = 0; | |
| 37 if (out) | |
| 38 *out = base::StringPiece(); | |
| 39 return true; | |
| 40 } | |
| 41 return false; | |
| 42 } | |
| 43 | |
| 44 size_t len = 0; | |
| 45 if ((data[1] & 0x80) == 0) { | |
| 46 // short form length | |
| 47 if (out_header_len) | |
| 48 *out_header_len = 2; | |
| 49 len = static_cast<size_t>(data[1]) + 2; | |
| 50 } else { | |
| 51 // long form length | |
| 52 const unsigned num_bytes = data[1] & 0x7f; | |
| 53 if (num_bytes == 0 || num_bytes > 2) | |
| 54 return false; | |
| 55 if (in->size() < 2 + num_bytes) | |
| 56 return false; | |
| 57 len = data[2]; | |
| 58 if (num_bytes == 2) { | |
| 59 if (len == 0) { | |
| 60 // the length encoding must be minimal. | |
| 61 return false; | |
| 62 } | |
| 63 len <<= 8; | |
| 64 len += data[3]; | |
| 65 } | |
| 66 if (len < 128) { | |
| 67 // the length should have been encoded in short form. This distinguishes | |
| 68 // DER from BER encoding. | |
| 69 return false; | |
| 70 } | |
| 71 if (out_header_len) | |
| 72 *out_header_len = 2 + num_bytes; | |
| 73 len += 2 + num_bytes; | |
| 74 } | |
| 75 | |
| 76 if (in->size() < len) | |
| 77 return false; | |
| 78 if (out) | |
| 79 *out = base::StringPiece(in->data(), len); | |
| 80 in->remove_prefix(len); | |
| 81 return true; | |
| 82 } | |
| 83 | |
| 84 bool GetElement(base::StringPiece* in, | |
| 85 unsigned tag_value, | |
| 86 base::StringPiece* out) { | |
| 87 unsigned header_len; | |
| 88 if (!ParseElement(in, tag_value, out, &header_len)) | |
| 89 return false; | |
| 90 if (out) | |
| 91 out->remove_prefix(header_len); | |
| 92 return true; | |
| 93 } | |
| 94 | |
| 95 // SeekToSPKI changes |cert| so that it points to a suffix of the | |
| 96 // TBSCertificate where the suffix begins at the start of the ASN.1 | |
| 97 // SubjectPublicKeyInfo value. | |
| 98 static bool SeekToSPKI(base::StringPiece* cert) { | |
| 99 // From RFC 5280, section 4.1 | |
| 100 // Certificate ::= SEQUENCE { | |
| 101 // tbsCertificate TBSCertificate, | |
| 102 // signatureAlgorithm AlgorithmIdentifier, | |
| 103 // signatureValue BIT STRING } | |
| 104 | |
| 105 // TBSCertificate ::= SEQUENCE { | |
| 106 // version [0] EXPLICIT Version DEFAULT v1, | |
| 107 // serialNumber CertificateSerialNumber, | |
| 108 // signature AlgorithmIdentifier, | |
| 109 // issuer Name, | |
| 110 // validity Validity, | |
| 111 // subject Name, | |
| 112 // subjectPublicKeyInfo SubjectPublicKeyInfo, | |
| 113 | |
| 114 base::StringPiece certificate; | |
| 115 if (!GetElement(cert, kSEQUENCE, &certificate)) | |
| 116 return false; | |
| 117 | |
| 118 // We don't allow junk after the certificate. | |
| 119 if (!cert->empty()) | |
| 120 return false; | |
| 121 | |
| 122 base::StringPiece tbs_certificate; | |
| 123 if (!GetElement(&certificate, kSEQUENCE, &tbs_certificate)) | |
| 124 return false; | |
| 125 | |
| 126 if (!GetElement(&tbs_certificate, | |
| 127 kOptional | kConstructed | kContextSpecific | 0, | |
| 128 NULL)) { | |
| 129 return false; | |
| 130 } | |
| 131 | |
| 132 // serialNumber | |
| 133 if (!GetElement(&tbs_certificate, kINTEGER, NULL)) | |
| 134 return false; | |
| 135 // signature | |
| 136 if (!GetElement(&tbs_certificate, kSEQUENCE, NULL)) | |
| 137 return false; | |
| 138 // issuer | |
| 139 if (!GetElement(&tbs_certificate, kSEQUENCE, NULL)) | |
| 140 return false; | |
| 141 // validity | |
| 142 if (!GetElement(&tbs_certificate, kSEQUENCE, NULL)) | |
| 143 return false; | |
| 144 // subject | |
| 145 if (!GetElement(&tbs_certificate, kSEQUENCE, NULL)) | |
| 146 return false; | |
| 147 *cert = tbs_certificate; | |
| 148 return true; | |
| 149 } | |
| 150 | |
| 151 bool ExtractSPKIFromDERCert(base::StringPiece cert, | |
| 152 base::StringPiece* spki_out) { | |
| 153 if (!SeekToSPKI(&cert)) | |
| 154 return false; | |
| 155 if (!ParseElement(&cert, kSEQUENCE, spki_out, NULL)) | |
| 156 return false; | |
| 157 return true; | |
| 158 } | |
| 159 | |
| 160 bool ExtractSubjectPublicKeyFromSPKI(base::StringPiece spki, | |
| 161 base::StringPiece* spk_out) { | |
| 162 // From RFC 5280, Section 4.1 | |
| 163 // SubjectPublicKeyInfo ::= SEQUENCE { | |
| 164 // algorithm AlgorithmIdentifier, | |
| 165 // subjectPublicKey BIT STRING } | |
| 166 // | |
| 167 // AlgorithmIdentifier ::= SEQUENCE { | |
| 168 // algorithm OBJECT IDENTIFIER, | |
| 169 // parameters ANY DEFINED BY algorithm OPTIONAL } | |
| 170 | |
| 171 // Step into SubjectPublicKeyInfo sequence. | |
| 172 base::StringPiece spki_contents; | |
| 173 if (!asn1::GetElement(&spki, asn1::kSEQUENCE, &spki_contents)) | |
| 174 return false; | |
| 175 | |
| 176 // Step over algorithm field (a SEQUENCE). | |
| 177 base::StringPiece algorithm; | |
| 178 if (!asn1::GetElement(&spki_contents, asn1::kSEQUENCE, &algorithm)) | |
| 179 return false; | |
| 180 | |
| 181 // Extract the subjectPublicKey field. | |
| 182 if (!asn1::GetElement(&spki_contents, asn1::kBITSTRING, spk_out)) | |
| 183 return false; | |
| 184 return true; | |
| 185 } | |
| 186 | |
| 187 | |
| 188 bool ExtractCRLURLsFromDERCert(base::StringPiece cert, | |
| 189 std::vector<base::StringPiece>* urls_out) { | |
| 190 urls_out->clear(); | |
| 191 std::vector<base::StringPiece> tmp_urls_out; | |
| 192 | |
| 193 if (!SeekToSPKI(&cert)) | |
| 194 return false; | |
| 195 | |
| 196 // From RFC 5280, section 4.1 | |
| 197 // TBSCertificate ::= SEQUENCE { | |
| 198 // ... | |
| 199 // subjectPublicKeyInfo SubjectPublicKeyInfo, | |
| 200 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, | |
| 201 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, | |
| 202 // extensions [3] EXPLICIT Extensions OPTIONAL | |
| 203 | |
| 204 // subjectPublicKeyInfo | |
| 205 if (!GetElement(&cert, kSEQUENCE, NULL)) | |
| 206 return false; | |
| 207 // issuerUniqueID | |
| 208 if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 1, NULL)) | |
| 209 return false; | |
| 210 // subjectUniqueID | |
| 211 if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 2, NULL)) | |
| 212 return false; | |
| 213 | |
| 214 base::StringPiece extensions_seq; | |
| 215 if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 3, | |
| 216 &extensions_seq)) { | |
| 217 return false; | |
| 218 } | |
| 219 | |
| 220 if (extensions_seq.empty()) | |
| 221 return true; | |
| 222 | |
| 223 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension | |
| 224 // Extension ::= SEQUENCE { | |
| 225 // extnID OBJECT IDENTIFIER, | |
| 226 // critical BOOLEAN DEFAULT FALSE, | |
| 227 // extnValue OCTET STRING | |
| 228 | |
| 229 // |extensions_seq| was EXPLICITly tagged, so we still need to remove the | |
| 230 // ASN.1 SEQUENCE header. | |
| 231 base::StringPiece extensions; | |
| 232 if (!GetElement(&extensions_seq, kSEQUENCE, &extensions)) | |
| 233 return false; | |
| 234 | |
| 235 while (extensions.size() > 0) { | |
| 236 base::StringPiece extension; | |
| 237 if (!GetElement(&extensions, kSEQUENCE, &extension)) | |
| 238 return false; | |
| 239 | |
| 240 base::StringPiece oid; | |
| 241 if (!GetElement(&extension, kOID, &oid)) | |
| 242 return false; | |
| 243 | |
| 244 // kCRLDistributionPointsOID is the DER encoding of the OID for the X.509 | |
| 245 // CRL Distribution Points extension. | |
| 246 static const uint8 kCRLDistributionPointsOID[] = {0x55, 0x1d, 0x1f}; | |
| 247 | |
| 248 if (oid.size() != sizeof(kCRLDistributionPointsOID) || | |
| 249 memcmp(oid.data(), kCRLDistributionPointsOID, oid.size()) != 0) { | |
| 250 continue; | |
| 251 } | |
| 252 | |
| 253 // critical | |
| 254 GetElement(&extension, kBOOLEAN, NULL); | |
| 255 | |
| 256 // extnValue | |
| 257 base::StringPiece extension_value; | |
| 258 if (!GetElement(&extension, kOCTETSTRING, &extension_value)) | |
| 259 return false; | |
| 260 | |
| 261 // RFC 5280, section 4.2.1.13. | |
| 262 // | |
| 263 // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint | |
| 264 // | |
| 265 // DistributionPoint ::= SEQUENCE { | |
| 266 // distributionPoint [0] DistributionPointName OPTIONAL, | |
| 267 // reasons [1] ReasonFlags OPTIONAL, | |
| 268 // cRLIssuer [2] GeneralNames OPTIONAL } | |
| 269 | |
| 270 base::StringPiece distribution_points; | |
| 271 if (!GetElement(&extension_value, kSEQUENCE, &distribution_points)) | |
| 272 return false; | |
| 273 | |
| 274 while (distribution_points.size() > 0) { | |
| 275 base::StringPiece distrib_point; | |
| 276 if (!GetElement(&distribution_points, kSEQUENCE, &distrib_point)) | |
| 277 return false; | |
| 278 | |
| 279 base::StringPiece name; | |
| 280 if (!GetElement(&distrib_point, kContextSpecific | kConstructed | 0, | |
| 281 &name)) { | |
| 282 // If it doesn't contain a name then we skip it. | |
| 283 continue; | |
| 284 } | |
| 285 | |
| 286 if (GetElement(&distrib_point, kContextSpecific | 1, NULL)) { | |
| 287 // If it contains a subset of reasons then we skip it. We aren't | |
| 288 // interested in subsets of CRLs and the RFC states that there MUST be | |
| 289 // a CRL that covers all reasons. | |
| 290 continue; | |
| 291 } | |
| 292 | |
| 293 if (GetElement(&distrib_point, | |
| 294 kContextSpecific | kConstructed | 2, NULL)) { | |
| 295 // If it contains a alternative issuer, then we skip it. | |
| 296 continue; | |
| 297 } | |
| 298 | |
| 299 // DistributionPointName ::= CHOICE { | |
| 300 // fullName [0] GeneralNames, | |
| 301 // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } | |
| 302 base::StringPiece general_names; | |
| 303 if (!GetElement(&name, | |
| 304 kContextSpecific | kConstructed | 0, &general_names)) { | |
| 305 continue; | |
| 306 } | |
| 307 | |
| 308 // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName | |
| 309 // GeneralName ::= CHOICE { | |
| 310 // ... | |
| 311 // uniformResourceIdentifier [6] IA5String, | |
| 312 // ... | |
| 313 while (general_names.size() > 0) { | |
| 314 base::StringPiece url; | |
| 315 if (GetElement(&general_names, kContextSpecific | 6, &url)) { | |
| 316 tmp_urls_out.push_back(url); | |
| 317 } else { | |
| 318 if (!GetElement(&general_names, kAny, NULL)) | |
| 319 return false; | |
| 320 } | |
| 321 } | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 urls_out->swap(tmp_urls_out); | |
| 326 return true; | |
| 327 } | |
| 328 | |
| 329 } // namespace asn1 | |
| 330 | |
| 331 } // namespace net | |
| OLD | NEW |