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/cert/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 332