This source file includes following definitions.
- ParseElement
 
- GetElement
 
- SeekToSPKI
 
- ExtractSPKIFromDERCert
 
- ExtractSubjectPublicKeyFromSPKI
 
- ExtractCRLURLsFromDERCert
 
#include "net/cert/asn1_util.h"
namespace net {
namespace asn1 {
bool ParseElement(base::StringPiece* in,
                  unsigned tag_value,
                  base::StringPiece* out,
                  unsigned *out_header_len) {
  const uint8* data = reinterpret_cast<const uint8*>(in->data());
  
  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 & 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) {
    
    if (out_header_len)
      *out_header_len = 2;
    len = static_cast<size_t>(data[1]) + 2;
  } else {
    
    const unsigned num_bytes = data[1] & 0x7f;
    if (num_bytes == 0 || num_bytes > 2)
      return false;
    if (in->size() < 2 + num_bytes)
      return false;
    len = data[2];
    if (num_bytes == 2) {
      if (len == 0) {
        
        return false;
      }
      len <<= 8;
      len += data[3];
    }
    if (len < 128) {
      
      
      return false;
    }
    if (out_header_len)
      *out_header_len = 2 + num_bytes;
    len += 2 + num_bytes;
  }
  if (in->size() < len)
    return false;
  if (out)
    *out = base::StringPiece(in->data(), len);
  in->remove_prefix(len);
  return true;
}
bool GetElement(base::StringPiece* in,
                unsigned tag_value,
                base::StringPiece* out) {
  unsigned header_len;
  if (!ParseElement(in, tag_value, out, &header_len))
    return false;
  if (out)
    out->remove_prefix(header_len);
  return true;
}
static bool SeekToSPKI(base::StringPiece* cert) {
  
  
  
  
  
  
  
  
  
  
  
  
  
  base::StringPiece certificate;
  if (!GetElement(cert, kSEQUENCE, &certificate))
    return false;
  
  if (!cert->empty())
    return false;
  base::StringPiece tbs_certificate;
  if (!GetElement(&certificate, kSEQUENCE, &tbs_certificate))
    return false;
  if (!GetElement(&tbs_certificate,
                  kOptional | kConstructed | kContextSpecific | 0,
                  NULL)) {
    return false;
  }
  
  if (!GetElement(&tbs_certificate, kINTEGER, NULL))
    return false;
  
  if (!GetElement(&tbs_certificate, kSEQUENCE, NULL))
    return false;
  
  if (!GetElement(&tbs_certificate, kSEQUENCE, NULL))
    return false;
  
  if (!GetElement(&tbs_certificate, kSEQUENCE, NULL))
    return false;
  
  if (!GetElement(&tbs_certificate, kSEQUENCE, NULL))
    return false;
  *cert = tbs_certificate;
  return true;
}
bool ExtractSPKIFromDERCert(base::StringPiece cert,
                            base::StringPiece* spki_out) {
  if (!SeekToSPKI(&cert))
    return false;
  if (!ParseElement(&cert, kSEQUENCE, spki_out, NULL))
    return false;
  return true;
}
bool ExtractSubjectPublicKeyFromSPKI(base::StringPiece spki,
                                     base::StringPiece* spk_out) {
  
  
  
  
  
  
  
  
  
  base::StringPiece spki_contents;
  if (!asn1::GetElement(&spki, asn1::kSEQUENCE, &spki_contents))
    return false;
  
  base::StringPiece algorithm;
  if (!asn1::GetElement(&spki_contents, asn1::kSEQUENCE, &algorithm))
    return false;
  
  if (!asn1::GetElement(&spki_contents, asn1::kBITSTRING, spk_out))
    return false;
  return true;
}
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;
  
  
  
  
  
  
  
  
  if (!GetElement(&cert, kSEQUENCE, NULL))
    return false;
  
  if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 1, NULL))
    return false;
  
  if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 2, NULL))
    return false;
  base::StringPiece extensions_seq;
  if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 3,
                  &extensions_seq)) {
    return false;
  }
  if (extensions_seq.empty())
    return true;
  
  
  
  
  
  
  
  base::StringPiece extensions;
  if (!GetElement(&extensions_seq, kSEQUENCE, &extensions))
    return false;
  while (extensions.size() > 0) {
    base::StringPiece extension;
    if (!GetElement(&extensions, kSEQUENCE, &extension))
      return false;
    base::StringPiece oid;
    if (!GetElement(&extension, kOID, &oid))
      return false;
    
    
    static const uint8 kCRLDistributionPointsOID[] = {0x55, 0x1d, 0x1f};
    if (oid.size() != sizeof(kCRLDistributionPointsOID) ||
        memcmp(oid.data(), kCRLDistributionPointsOID, oid.size()) != 0) {
      continue;
    }
    
    GetElement(&extension, kBOOLEAN, NULL);
    
    base::StringPiece extension_value;
    if (!GetElement(&extension, kOCTETSTRING, &extension_value))
      return false;
    
    
    
    
    
    
    
    
    base::StringPiece distribution_points;
    if (!GetElement(&extension_value, kSEQUENCE, &distribution_points))
      return false;
    while (distribution_points.size() > 0) {
      base::StringPiece distrib_point;
      if (!GetElement(&distribution_points, kSEQUENCE, &distrib_point))
        return false;
      base::StringPiece name;
      if (!GetElement(&distrib_point, kContextSpecific | kConstructed | 0,
                      &name)) {
        
        continue;
      }
      if (GetElement(&distrib_point, kContextSpecific | 1, NULL)) {
        
        
        
        continue;
      }
      if (GetElement(&distrib_point,
                     kContextSpecific | kConstructed | 2, NULL)) {
        
        continue;
      }
      
      
      
      base::StringPiece general_names;
      if (!GetElement(&name,
                      kContextSpecific | kConstructed | 0, &general_names)) {
        continue;
      }
      
      
      
      
      
      while (general_names.size() > 0) {
        base::StringPiece url;
        if (GetElement(&general_names, kContextSpecific | 6, &url)) {
          tmp_urls_out.push_back(url);
        } else {
          if (!GetElement(&general_names, kAny, NULL))
            return false;
        }
      }
    }
  }
  urls_out->swap(tmp_urls_out);
  return true;
}
} 
}