// Copyright 2015 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BSSL_DER_PARSER_H_ #define BSSL_DER_PARSER_H_ #include <stdint.h> #include <optional> #include <openssl/base.h> #include <openssl/bytestring.h> #include "input.h" BSSL_NAMESPACE_BEGIN namespace der { class BitString; struct GeneralizedTime; // Parses a DER-encoded ASN.1 structure. DER (distinguished encoding rules) // encodes each data value with a tag, length, and value (TLV). The tag // indicates the type of the ASN.1 value. Depending on the type of the value, // it could contain arbitrary bytes, so the length of the value is encoded // after the tag and before the value to indicate how many bytes of value // follow. DER also defines how the values are encoded for particular types. // // This Parser places a few restrictions on the DER encoding it can parse. The // largest restriction is that it only supports tags which have a tag number // no greater than 30 - these are the tags that fit in a single octet. The // second restriction is that the maximum length for a value that can be parsed // is 4GB. Both of these restrictions should be fine for any reasonable input. // // The Parser class is mainly focused on parsing the TLV structure of DER // encoding, and does not directly handle parsing primitive values (other // functions in the bssl::der namespace are provided for this.) When a Parser // is created, it is passed in a reference to the encoded data. Because the // encoded data is not owned by the Parser, the data cannot change during the // lifespan of the Parser. The Parser functions by keeping a pointer to the // current TLV which starts at the beginning of the input and advancing through // the input as each TLV is read. As such, a Parser instance is thread-unsafe. // // Most methods for using the Parser write the current tag and/or value to // the output parameters provided and then advance the input to the next TLV. // None of the methods explicitly expose the length because it is part of the // value. All methods return a boolean indicating whether there was a parsing // error with the current TLV. // // Some methods are provided in the Parser class as convenience to both read // the current TLV from the input and also parse the DER encoded value, // converting it to a corresponding C++ type. These methods simply combine // ReadTag() with the appropriate ParseType() free function. // // The design of DER encoding allows for nested data structures with // constructed values, where the value is a series of TLVs. The Parser class // is not designed to traverse through a nested encoding from a single object, // but it does facilitate parsing nested data structures through the // convenience methods ReadSequence() and the more general ReadConstructed(), // which provide the user with another Parser object to traverse the next // level of TLVs. // // For a brief example of how to use the Parser, suppose we have the following // ASN.1 type definition: // // Foo ::= SEQUENCE { // bar OCTET STRING OPTIONAL, // quux OCTET STRING } // // If we have a DER-encoded Foo in an Input |encoded_value|, the // following code shows an example of how to parse the quux field from the // encoded data. // // bool ReadQuux(Input encoded_value, Input* quux_out) { // Parser parser(encoded_value); // Parser foo_parser; // if (!parser.ReadSequence(&foo_parser)) // return false; // if (!foo_parser->SkipOptionalTag(kOctetString)) // return false; // if (!foo_parser->ReadTag(kOctetString, quux_out)) // return false; // return true; // } class OPENSSL_EXPORT Parser { … }; } // namespace der BSSL_NAMESPACE_END #endif // BSSL_DER_PARSER_H_