Chromium Code Reviews| Index: net/cert/ocsp_parser.cc |
| diff --git a/net/cert/ocsp_parser.cc b/net/cert/ocsp_parser.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8672dbff9157436b8ddf902e28596366d57a1499 |
| --- /dev/null |
| +++ b/net/cert/ocsp_parser.cc |
| @@ -0,0 +1,255 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "net/cert/ocsp_parser.h" |
| + |
| +namespace net { |
| + |
| +namespace ct { |
| + |
| +namespace { |
| + |
| +bool ParseOCSPSingleResponse(der::Parser* parser, OCSPSingleResponse* data) { |
| + der::Input cert_id; |
| + if (!parser->ReadTag(der::kSequence, &cert_id)) |
| + return false; |
| + data->cert_id = cert_id.AsString(); |
| + der::Tag status_tag; |
| + der::Input status; |
| + if (!parser->ReadTagAndValue(&status_tag, &status)) |
| + return false; |
| + if (status_tag == der::ContextSpecificPrimitive(0)) { |
| + data->cert_status = OCSP_CERT_GOOD; |
| + } else if (status_tag == der::ContextSpecificPrimitive(1)) { |
| + data->cert_status = OCSP_CERT_REVOKED; |
| + der::Parser revoked_info_parser(status); |
| + der::Input revocation_time; |
| + der::Input revocation_reason; |
| + if (!revoked_info_parser.ReadTag(der::kGeneralizedTime, &revocation_time)) |
| + return false; |
| + if (!der::ParseGeneralizedTime(revocation_time, &(data->revocation_time))) |
| + return false; |
| + if (!revoked_info_parser.ReadTag(der::kEnumerated, &revocation_reason)) |
| + return false; |
| + uint8_t revocation_reason_value; |
| + if (!der::ParseUint8(revocation_reason, &revocation_reason_value)) |
| + return false; |
| + data->revocation_reason = |
| + static_cast<OCSPRevocationReason>(revocation_reason_value); |
| + } else if (status_tag == der::ContextSpecificPrimitive(2)) { |
| + data->cert_status = OCSP_CERT_UNKNOWN; |
| + } |
|
Ryan Sleevi
2015/12/30 18:55:18
BUG: Fail to handle other status tags.
svaldez
2015/12/30 19:31:37
Done.
|
| + |
| + der::Input this_update; |
| + if (!parser->ReadTag(der::kGeneralizedTime, &this_update)) |
| + return false; |
| + if (!der::ParseGeneralizedTime(this_update, &(data->this_update))) |
| + return false; |
| + der::Input next_update_input; |
| + bool next_update_present; |
| + if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(0), |
| + &next_update_input, &next_update_present)) { |
| + return false; |
| + } |
| + |
| + if (next_update_present) { |
| + der::Parser next_update_parser(next_update_input); |
| + der::Input next_update; |
| + if (!next_update_parser.ReadTag(der::kGeneralizedTime, &next_update)) |
| + return false; |
| + if (!der::ParseGeneralizedTime(next_update, &(data->next_update))) |
| + return false; |
| + } |
| + der::Input extensions_input; |
| + bool extensions_present; |
| + if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(1), |
| + &extensions_input, &extensions_present)) { |
| + return false; |
| + } |
| + |
| + if (!extensions_present) |
| + return true; |
| + der::Parser extensions_input_parser(extensions_input); |
| + der::Parser extensions_parser; |
| + if (!extensions_input_parser.ReadSequence(&extensions_parser)) |
| + return false; |
| + while (extensions_parser.HasMore()) { |
| + ParsedExtension extension; |
| + der::Input extension_tlv; |
| + if (!extensions_parser.ReadRawTLV(&extension_tlv)) |
| + return false; |
| + if (!ParseExtension(extension_tlv, &extension)) |
| + return false; |
| + data->extensions.push_back(extension); |
| + } |
| + return true; |
| +} |
| + |
| +bool ParseOCSPResponseData(der::Parser* parser, OCSPResponseData* data) { |
| + der::Input version_input; |
| + bool version_present; |
| + if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(0), |
| + &version_input, &version_present)) { |
| + return false; |
| + } |
| + if (version_present) { |
|
Ryan Sleevi
2015/12/30 18:55:18
newline
svaldez
2015/12/30 19:31:37
Done.
|
| + der::Parser version_parser(version_input); |
| + der::Input version; |
| + if (!version_parser.ReadTag(der::kInteger, &version)) |
| + return false; |
| + if (!der::ParseUint8(version, &(data->version))) |
| + return false; |
| + } else { |
| + data->version = 0; |
| + } |
| + |
| + der::Tag id_tag; |
| + der::Input responder_id; |
| + if (!parser->ReadTagAndValue(&id_tag, &responder_id)) |
| + return false; |
| + if (id_tag == der::ContextSpecificConstructed(1)) { |
| + data->responder_id_name = responder_id.AsString(); |
| + } else if (id_tag == der::ContextSpecificConstructed(2)) { |
| + der::Parser key_parser(responder_id); |
| + der::Input responder_key; |
| + if (!key_parser.ReadTag(der::kOctetString, &responder_key)) |
| + return false; |
| + data->responder_id_key = responder_key.AsString(); |
| + } else { |
| + return false; |
| + } |
| + |
| + der::Input produced_at; |
| + if (!parser->ReadTag(der::kGeneralizedTime, &produced_at)) |
| + return false; |
| + if (!der::ParseGeneralizedTime(produced_at, &(data->produced_at))) |
| + return false; |
| + |
| + der::Parser responses_parser; |
| + if (!parser->ReadSequence(&responses_parser)) |
| + return false; |
| + while (responses_parser.HasMore()) { |
| + OCSPSingleResponse single_response; |
| + der::Parser response_parser; |
| + if (!responses_parser.ReadSequence(&response_parser)) |
| + return false; |
| + if (!ParseOCSPSingleResponse(&response_parser, &single_response)) |
| + return false; |
| + data->responses.push_back(single_response); |
| + } |
| + |
| + der::Input extensions_input; |
| + bool extensions_present; |
| + if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(1), |
| + &extensions_input, &extensions_present)) { |
| + return false; |
| + } |
| + |
| + if (!extensions_present) |
| + return true; |
| + der::Parser extensions_input_parser(extensions_input); |
| + der::Parser extensions_parser; |
| + if (!extensions_input_parser.ReadSequence(&extensions_parser)) |
| + return false; |
| + while (extensions_parser.HasMore()) { |
| + ParsedExtension extension; |
| + der::Input extension_tlv; |
| + if (!extensions_parser.ReadRawTLV(&extension_tlv)) |
| + return false; |
| + if (!ParseExtension(extension_tlv, &extension)) |
| + return false; |
| + data->extensions.push_back(extension); |
| + } |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +OCSPSingleResponse::OCSPSingleResponse() {} |
| +OCSPSingleResponse::~OCSPSingleResponse() {} |
| + |
| +OCSPResponseData::OCSPResponseData() {} |
| +OCSPResponseData::~OCSPResponseData() {} |
| + |
| +OCSPResponse::OCSPResponse() {} |
| +OCSPResponse::~OCSPResponse() {} |
| + |
| +bool ParseOCSPResponse(const std::string& ocsp_response, |
| + OCSPResponse* response) { |
| + der::Parser parser( |
| + der::Input(reinterpret_cast<const uint8_t*>(ocsp_response.data()), |
| + ocsp_response.size())); |
| + der::Input response_status; |
| + der::Parser ocsp_response_parser; |
| + if (!parser.ReadSequence(&ocsp_response_parser)) |
| + return false; |
| + if (!ocsp_response_parser.ReadTag(der::kEnumerated, &response_status)) |
| + return false; |
| + uint8_t response_status_value; |
| + if (!der::ParseUint8(response_status, &response_status_value)) |
| + return false; |
| + response->status = static_cast<OCSPResponseStatus>(response_status_value); |
| + if (response->status != OCSP_SUCCESSFUL) |
| + return true; |
| + |
| + der::Input response_type_oid; |
| + der::Input response_string; |
| + der::Parser response_bytes_input_parser; |
| + der::Parser response_bytes_parser; |
| + if (!ocsp_response_parser.ReadConstructed(der::ContextSpecificConstructed(0), |
| + &response_bytes_input_parser)) { |
| + return false; |
| + } |
| + if (!response_bytes_input_parser.ReadSequence(&response_bytes_parser)) |
| + return false; |
| + if (!response_bytes_parser.ReadTag(der::kOid, &response_type_oid)) |
| + return false; |
| + if (!response_type_oid.Equals(der::Input(kOidPkixOcspBasic))) |
| + return false; |
| + if (!response_bytes_parser.ReadTag(der::kOctetString, &response_string)) |
| + return false; |
| + |
| + der::Parser response_parser(response_string); |
| + der::Parser basic_response_parser; |
| + der::Parser response_data_parser; |
| + der::Input sigalg_tlv; |
| + if (!response_parser.ReadSequence(&basic_response_parser)) |
| + return false; |
| + if (!basic_response_parser.ReadSequence(&response_data_parser)) |
| + return false; |
| + if (!ParseOCSPResponseData(&response_data_parser, &(response->data))) |
| + return false; |
| + if (!basic_response_parser.ReadRawTLV(&sigalg_tlv)) |
| + return false; |
| + response->signature_algorithm = SignatureAlgorithm::CreateFromDer(sigalg_tlv); |
| + if (!basic_response_parser.ReadBitString(&(response->signature))) |
| + return false; |
| + der::Input certs_input; |
| + bool certs_present; |
| + if (!basic_response_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), |
| + &certs_input, &certs_present)) { |
| + return false; |
| + } |
| + |
| + if (!certs_present) |
| + return true; |
| + der::Parser certs_input_parser(certs_input); |
| + der::Parser certs_parser; |
| + if (!certs_input_parser.ReadSequence(&certs_parser)) |
| + return false; |
| + while (certs_parser.HasMore()) { |
| + ParsedCertificate parsed_cert; |
| + der::Input cert_tlv; |
| + if (!certs_parser.ReadRawTLV(&cert_tlv)) |
| + return false; |
| + if (!ParseCertificate(cert_tlv, &parsed_cert)) |
| + return false; |
| + response->certs.push_back(parsed_cert); |
| + } |
| + return true; |
| +} |
| + |
| +} // namespace cert |
| + |
| +} // namespace net |