| // Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #ifndef OPENSSL_HEADER_CRYPTO_ASN1_INTERNAL_H | |
| #define OPENSSL_HEADER_CRYPTO_ASN1_INTERNAL_H | |
| #include <time.h> | |
| #include <openssl/asn1.h> | |
| #include <openssl/asn1t.h> | |
| #include <openssl/span.h> | |
| #include "../internal.h" | |
| BSSL_NAMESPACE_BEGIN | |
| // Wrapper functions for time functions. | |
| // OPENSSL_gmtime converts a time_t value in `time` which must be in the range | |
| // of year 0000 to 9999 to a broken out time value in `tm`. On success `tm` is | |
| // returned. On failure NULL is returned. | |
| OPENSSL_EXPORT struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result); | |
| // OPENSSL_gmtime_adj returns one on success, and updates `tm` by adding | |
| // `offset_day` days and `offset_sec` seconds. It returns zero on failure. `tm` | |
| // must be in the range of year 0000 to 9999 both before and after the update or | |
| // a failure will be returned. | |
| OPENSSL_EXPORT int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, | |
| int64_t offset_sec); | |
| // OPENSSL_gmtime_diff calculates the difference between `from` and `to`. It | |
| // returns one, and outputs the difference as a number of days and seconds in | |
| // `*out_days` and `*out_secs` on success. It returns zero on failure. Both | |
| // `from` and `to` must be in the range of year 0000 to 9999 or a failure will | |
| // be returned. | |
| OPENSSL_EXPORT int OPENSSL_gmtime_diff(int *out_days, int *out_secs, | |
| const struct tm *from, | |
| const struct tm *to); | |
| // Object identifiers. | |
| // These are used internally in the ASN1_OBJECT to keep track of | |
| // whether the names and data need to be free()ed | |
| #define ASN1_OBJECT_FLAG_DYNAMIC 0x01 // internal use | |
| #define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 // internal use | |
| #define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 // internal use | |
| BSSL_NAMESPACE_END | |
| // An asn1_object_st (aka `ASN1_OBJECT`) represents an ASN.1 OBJECT IDENTIFIER. | |
| // Note: Mutating an `ASN1_OBJECT` is only permitted when initializing it. The | |
| // library maintains a table of static `ASN1_OBJECT`s, which may be referenced | |
| // by non-const `ASN1_OBJECT` pointers. Code which receives an `ASN1_OBJECT` | |
| // pointer externally must assume it is immutable, even if the pointer is not | |
| // const. | |
| struct asn1_object_st { | |
| const char *sn, *ln; | |
| int nid; | |
| int length; | |
| const unsigned char *data; // data remains const after init | |
| int flags; // Should we free this one | |
| }; | |
| BSSL_NAMESPACE_BEGIN | |
| ASN1_OBJECT *ASN1_OBJECT_new(); | |
| // asn1_parse_object parses a DER-encoded ASN.1 OBJECT IDENTIFIER from `cbs` and | |
| // write the result to `out`. If `tag` is non-zero, the value is implicitly | |
| // tagged with `tag`. On success, it returns a newly-allocated `ASN1_OBJECT` | |
| // with the result and advances `cbs` past the parsed element. | |
| // | |
| // TODO(crbug.com/boringssl/414361735): This should return a bssl::UniquePtr, | |
| // but cannot until it is made C++ linkage. | |
| ASN1_OBJECT *asn1_parse_object(CBS *cbs, CBS_ASN1_TAG tag); | |
| // asn1_marshal_object marshals `in` as a DER-encoded, ASN.1 OBJECT IDENTIFIER | |
| // and writes the result to `out`. It returns one on success and zero on error. | |
| // If `tag` is non-zero, the tag is replaced with `tag`. | |
| int asn1_marshal_object(CBB *out, const ASN1_OBJECT *in, CBS_ASN1_TAG tag); | |
| // Strings. | |
| // asn1_is_printable returns one if `value` is a valid Unicode codepoint for an | |
| // ASN.1 PrintableString, and zero otherwise. | |
| int asn1_is_printable(uint32_t value); | |
| // asn1_string_init initializes `str`, which may be uninitialized, with type | |
| // `type`. | |
| void asn1_string_init(ASN1_STRING *str, int type); | |
| // asn1_string_cleanup releases memory associated with `str`'s value, without | |
| // freeing `str` itself. | |
| void asn1_string_cleanup(ASN1_STRING *str); | |
| // A ScopedASN1String is a stack-allocatable `ASN1_STRING` with managed | |
| // lifetime. | |
| // TODO(crbug.com/443769299): Once `ASN1_STRING` is no longer public, this can | |
| // instead use `DECLARE_OPAQUE_STRUCT`. | |
| class ScopedASN1String { | |
| public: | |
| explicit ScopedASN1String(int type) { asn1_string_init(&str_, type); } | |
| ScopedASN1String(const ScopedASN1String &) = delete; | |
| ScopedASN1String &operator=(const ScopedASN1String &) = delete; | |
| ~ScopedASN1String() { asn1_string_cleanup(&str_); } | |
| ASN1_STRING *get() { return &str_; } | |
| const ASN1_STRING *get() const { return &str_; } | |
| ASN1_STRING *operator->() { return &str_; } | |
| const ASN1_STRING *operator->() const { return &str_; } | |
| private: | |
| ASN1_STRING str_; | |
| }; | |
| // asn1_parse_string_unchecked parses a DER-encoded string of type `str_type`, | |
| // tagged with `tag`. It does not check the contents. | |
| int asn1_parse_string_unchecked(CBS *cbs, ASN1_STRING *out, int str_type, | |
| CBS_ASN1_TAG tag); | |
| // The following functions parse a DER-encoded ASN.1 value of the specified | |
| // type from `cbs` and write the result to `*out`. If `tag` is non-zero, the | |
| // value is implicitly tagged with `tag`. On success, they return one and | |
| // advance `cbs` past the parsed element. On entry, `*out` must contain an | |
| // `ASN1_STRING` in some valid state. | |
| int asn1_parse_bit_string(CBS *cbs, ASN1_BIT_STRING *out, CBS_ASN1_TAG tag); | |
| int asn1_parse_integer(CBS *cbs, ASN1_INTEGER *out, CBS_ASN1_TAG tag); | |
| int asn1_parse_enumerated(CBS *cbs, ASN1_ENUMERATED *out, CBS_ASN1_TAG tag); | |
| int asn1_parse_octet_string(CBS *cbs, ASN1_STRING *out, CBS_ASN1_TAG tag); | |
| int asn1_parse_t61_string(CBS *cbs, ASN1_STRING *out, CBS_ASN1_TAG tag); | |
| int asn1_parse_bmp_string(CBS *cbs, ASN1_BMPSTRING *out, CBS_ASN1_TAG tag); | |
| int asn1_parse_universal_string(CBS *cbs, ASN1_UNIVERSALSTRING *out, | |
| CBS_ASN1_TAG tag); | |
| int asn1_parse_utf8_string(CBS *cbs, ASN1_UNIVERSALSTRING *out, | |
| CBS_ASN1_TAG tag); | |
| int asn1_parse_generalized_time(CBS *cbs, ASN1_GENERALIZEDTIME *out, | |
| CBS_ASN1_TAG tag); | |
| int asn1_parse_utc_time(CBS *cbs, ASN1_UTCTIME *out, CBS_ASN1_TAG tag, | |
| int allow_timezone_offset); | |
| // asn1_parse_bit_string_with_bad_length behaves like `asn1_parse_bit_string` | |
| // but tolerates BER non-minimal, definite lengths. | |
| int asn1_parse_bit_string_with_bad_length(CBS *cbs, ASN1_BIT_STRING *out); | |
| // asn1_marshal_bit_string marshals `in` as a DER-encoded, ASN.1 BIT STRING and | |
| // writes the result to `out`. It returns one on success and zero on error. If | |
| // `tag` is non-zero, the tag is replaced with `tag`. | |
| int asn1_marshal_bit_string(CBB *out, const ASN1_BIT_STRING *in, | |
| CBS_ASN1_TAG tag); | |
| // asn1_marshal_integer marshals `in` as a DER-encoded, ASN.1 INTEGER and writes | |
| // the result to `out`. It returns one on success and zero on error. If `tag` is | |
| // non-zero, the tag is replaced with `tag`. This can also be used to marshal an | |
| // ASN.1 ENUMERATED value by overriding the tag. | |
| int asn1_marshal_integer(CBB *out, const ASN1_INTEGER *in, CBS_ASN1_TAG tag); | |
| // asn1_marshal_octet_string marshals `in` as a DER-encoded, ASN.1 OCTET STRING | |
| // and writes the result to `out`. It returns one on success and zero on error. | |
| // If `tag` is non-zero, the tag is replaced with `tag`. | |
| // | |
| // This function may be used to marshal other string-based universal types whose | |
| // encoding is that of an implicitly-tagged OCTET STRING, e.g. UTF8String. | |
| int asn1_marshal_octet_string(CBB *out, const ASN1_STRING *in, | |
| CBS_ASN1_TAG tag); | |
| OPENSSL_EXPORT int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d, | |
| int allow_timezone_offset); | |
| OPENSSL_EXPORT int asn1_generalizedtime_to_tm(struct tm *tm, | |
| const ASN1_GENERALIZEDTIME *d); | |
| int asn1_parse_time(CBS *cbs, ASN1_TIME *out, int allow_utc_timezone_offset); | |
| int asn1_marshal_time(CBB *cbb, const ASN1_TIME *in); | |
| // The ASN.1 ANY type. | |
| // asn1_type_value_as_pointer returns `a`'s value in pointer form. This is | |
| // usually the value object but, for BOOLEAN values, is 0 or 0xff cast to | |
| // a pointer. | |
| const void *asn1_type_value_as_pointer(const ASN1_TYPE *a); | |
| // asn1_type_set0_string sets `a`'s value to the object represented by `str` and | |
| // takes ownership of `str`. | |
| void asn1_type_set0_string(ASN1_TYPE *a, ASN1_STRING *str); | |
| // asn1_parse_any parses a DER-encoded ASN.1 value of any type from `cbs` and | |
| // writes the result to `*out`. On success, it advances `cbs` past the parsed | |
| // element and returns one. On entry, `*out` must contain an `ASN1_TYPE` in some | |
| // valid state. | |
| int asn1_parse_any(CBS *cbs, ASN1_TYPE *out); | |
| // asn1_parse_any_as_string behaves like `asn1_parse_any` but represents the | |
| // value as an `ASN1_STRING`. Types which are not represented with | |
| // `ASN1_STRING`, such as `ASN1_OBJECT`, are represented with type | |
| // `V_ASN1_OTHER`. | |
| int asn1_parse_any_as_string(CBS *cbs, ASN1_STRING *out); | |
| // asn1_marshal_any marshals `in` as a DER-encoded ASN.1 value and writes the | |
| // result to `out`. It returns one on success and zero on error. | |
| int asn1_marshal_any(CBB *out, const ASN1_TYPE *in); | |
| // asn1_marshal_any_string marshals `in` as a DER-encoded ASN.1 value and writes | |
| // the result to `out`. It returns one on success and zero on error. | |
| int asn1_marshal_any_string(CBB *out, const ASN1_STRING *in); | |
| // Support structures for the template-based encoder. | |
| // ASN1_ENCODING is used to save the received encoding of an ASN.1 type. This | |
| // avoids problems with invalid encodings that break signatures. | |
| typedef struct ASN1_ENCODING_st { | |
| // enc is the saved DER encoding. Its ownership is determined by `buf`. | |
| uint8_t *enc; | |
| // len is the length of `enc`. If zero, there is no saved encoding. | |
| size_t len; | |
| } ASN1_ENCODING; | |
| int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); | |
| void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| // asn1_load_ptr returns `*pval`, but without asserting `*pval`'s underlying | |
| // type for strict aliasing. This helper must be used when the field's | |
| // underlying type is not known statically. It must not be used for | |
| // `ASN1_BOOLEAN` fields, which are not a pointers. | |
| inline ASN1_VALUE *asn1_load_ptr(ASN1_VALUE **pval) { | |
| ASN1_VALUE *ret; | |
| OPENSSL_memcpy(&ret, pval, sizeof(ASN1_VALUE *)); | |
| return ret; | |
| } | |
| // asn1_load_ptr_as behaves like `asn1_load_ptr`, but casts the result to `T*`. | |
| template <typename T> | |
| inline T *asn1_load_ptr_as(ASN1_VALUE **pval) { | |
| return reinterpret_cast<T *>(asn1_load_ptr(pval)); | |
| } | |
| // asn1_store_ptr sets `*pval` to `v`, but without asserting `*pval`'s | |
| // underlying type for strict aliasing. This helper must be used when the | |
| // field's underlying type is not known statically. It must not be used for | |
| // `ASN1_BOOLEAN` fields, which are not a pointers. | |
| inline void asn1_store_ptr(ASN1_VALUE **pval, const void *v) { | |
| OPENSSL_memcpy(pval, &v, sizeof(v)); | |
| } | |
| // asn1_get_choice_selector returns the CHOICE selector value for `*pval`, which | |
| // must of type `it`. | |
| int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it); | |
| // asn1_get_field_ptr returns a pointer to the field in `*pval` corresponding to | |
| // `tt`. | |
| ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); | |
| // asn1_do_adb returns the `ASN1_TEMPLATE` for the ANY DEFINED BY field `tt`, | |
| // based on the selector INTEGER or OID in `*pval`. If `tt` is not an ADB field, | |
| // it returns `tt`. If the selector does not match any value, it returns NULL. | |
| // If `nullerr` is non-zero, it will additionally push an error to the error | |
| // queue when there is no match. | |
| const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, | |
| int nullerr); | |
| void asn1_refcount_set_one(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| int asn1_refcount_dec_and_test_zero(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| // asn1_enc_restore, if `*pval` has a saved encoding, sets `*out` to it, and | |
| // returns one. If it has no saved encoding, it returns zero. | |
| int asn1_enc_restore(Span<const uint8_t> *out, ASN1_VALUE **pval, | |
| const ASN1_ITEM *it); | |
| // asn1_enc_save saves `inlen` bytes from `in` as `*pval`'s saved encoding. It | |
| // returns one on success and zero on error. If `buf` is non-NULL, `in` must | |
| // point into `buf`. | |
| int asn1_enc_save(ASN1_VALUE **pval, const uint8_t *in, size_t inlen, | |
| const ASN1_ITEM *it); | |
| // asn1_encoding_clear clears the cached encoding in `enc`. | |
| void asn1_encoding_clear(ASN1_ENCODING *enc); | |
| // asn1_tag_to_cbs converts a tag from this library's representation (the | |
| // `V_ASN1_*` constants) to that of `CBS` and `CBB`. It returns the tag on | |
| // success and zero if the input could not be represented. (Zero would be | |
| // [UNIVERSAL 0], which is a reserved tag value.) | |
| // | |
| // The resulting tag will not have the constructed bit set. The caller must OR | |
| // the result with `CBS_ASN1_CONSTRUCTED` if necessary, before passing to | |
| // `CBS` and `CBB` functions. | |
| CBS_ASN1_TAG asn1_tag_to_cbs(int aclass, int tag); | |
| typedef struct { | |
| int nid; | |
| long minsize; | |
| long maxsize; | |
| unsigned long mask; | |
| unsigned long flags; | |
| } ASN1_STRING_TABLE; | |
| // asn1_get_string_table_for_testing sets `*out_ptr` and `*out_len` to the table | |
| // of built-in `ASN1_STRING_TABLE` values. It is exported for testing. | |
| OPENSSL_EXPORT void asn1_get_string_table_for_testing( | |
| const ASN1_STRING_TABLE **out_ptr, size_t *out_len); | |
| typedef ASN1_VALUE *ASN1_new_func(); | |
| typedef void ASN1_free_func(ASN1_VALUE *a); | |
| typedef ASN1_VALUE *ASN1_d2i_func(ASN1_VALUE **a, const unsigned char **in, | |
| long length); | |
| typedef int ASN1_i2d_func(ASN1_VALUE *a, unsigned char **in); | |
| // An ASN1_ex_parse function should parse a value from `cbs` and set `*pval` to | |
| // the result. It should return one on success and zero on failure. If `opt` is | |
| // non-zero, the field may be optional. If an optional element is missing, the | |
| // function should return one and consume zero bytes from `cbs`. | |
| // | |
| // If `opt` is non-zero, the function can assume that `*pval` is nullptr on | |
| // entry. Otherwise, `*pval` may either be nullptr, or the result of | |
| // `ASN1_ex_new_func`. The function may either write into the existing object, | |
| // if any, or unconditionally make a new one. (The existing object comes from | |
| // tasn_new.cc recursively filling in objects before parsing into them.) | |
| typedef int ASN1_ex_parse(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |
| int opt); | |
| // An ASN1_ex_marshal function should marshal `*pval`, a value of type `it`, to | |
| // `cbb` and return one on success or zero on error. | |
| typedef int ASN1_ex_marshal(CBB *cbb, ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
| typedef struct ASN1_EXTERN_FUNCS_st { | |
| ASN1_ex_new_func *asn1_ex_new; | |
| ASN1_ex_free_func *asn1_ex_free; | |
| ASN1_ex_parse *asn1_ex_parse; | |
| ASN1_ex_marshal *asn1_ex_marshal; | |
| } ASN1_EXTERN_FUNCS; | |
| // IMPLEMENT_EXTERN_ASN1_PARSE_NEW implements an `ASN1_ITEM` for a type whose | |
| // parse function returns a new object. | |
| #define IMPLEMENT_EXTERN_ASN1_PARSE_NEW(name, new_func, free_func, tag, \ | |
| parse_func, marshal_func) \ | |
| static int name##_new_cb(ASN1_VALUE **pval, const ASN1_ITEM *it) { \ | |
| name *obj = new_func(); \ | |
| if (obj == nullptr) { \ | |
| return 0; \ | |
| } \ | |
| asn1_store_ptr(pval, obj); \ | |
| return 1; \ | |
| } \ | |
| \ | |
| static void name##_free_cb(ASN1_VALUE **pval, const ASN1_ITEM *it) { \ | |
| free_func(asn1_load_ptr_as<name>(pval)); \ | |
| asn1_store_ptr(pval, nullptr); \ | |
| } \ | |
| \ | |
| static int name##_parse_cb(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, \ | |
| int opt) { \ | |
| if (opt && !CBS_peek_asn1_tag(cbs, (tag))) { \ | |
| return 1; \ | |
| } \ | |
| \ | |
| bssl::UniquePtr<name> ret = parse_func(cbs); \ | |
| if (ret == nullptr) { \ | |
| return 0; \ | |
| } \ | |
| name##_free_cb(pval, it); \ | |
| asn1_store_ptr(pval, ret.release()); \ | |
| return 1; \ | |
| } \ | |
| \ | |
| static int name##_marshal_cb(CBB *cbb, ASN1_VALUE **pval, \ | |
| const ASN1_ITEM *it) { \ | |
| return marshal_func(cbb, asn1_load_ptr_as<name>(pval)); \ | |
| } \ | |
| \ | |
| static const ASN1_EXTERN_FUNCS name##_extern_funcs = { \ | |
| name##_new_cb, name##_free_cb, name##_parse_cb, name##_marshal_cb}; \ | |
| \ | |
| IMPLEMENT_EXTERN_ASN1(name, name##_extern_funcs) | |
| // IMPLEMENT_EXTERN_ASN1_PARSE_INTO implements an `ASN1_ITEM` for a type whose | |
| // parse function writes into an existing object. | |
| #define IMPLEMENT_EXTERN_ASN1_PARSE_INTO(name, new_func, free_func, tag, \ | |
| parse_func, marshal_func) \ | |
| \ | |
| static bssl::UniquePtr<name> name##_parse_new(CBS *cbs) { \ | |
| bssl::UniquePtr<name> ret(new_func()); \ | |
| if (ret == nullptr || !parse_func(cbs, ret.get())) { \ | |
| return 0; \ | |
| } \ | |
| return ret; \ | |
| } \ | |
| \ | |
| IMPLEMENT_EXTERN_ASN1_PARSE_NEW(name, new_func, free_func, tag, \ | |
| name##_parse_new, marshal_func) | |
| // ASN1_TIME is an `ASN1_ITEM` whose ASN.1 type is X.509 Time (RFC 5280) and C | |
| // type is `ASN1_TIME*`. | |
| DECLARE_ASN1_ITEM(ASN1_TIME) | |
| // DIRECTORYSTRING is an `ASN1_ITEM` whose ASN.1 type is X.509 DirectoryString | |
| // (RFC 5280) and C type is `ASN1_STRING*`. | |
| DECLARE_ASN1_ITEM(DIRECTORYSTRING) | |
| // DISPLAYTEXT is an `ASN1_ITEM` whose ASN.1 type is X.509 DisplayText (RFC | |
| // 5280) and C type is `ASN1_STRING*`. | |
| DECLARE_ASN1_ITEM(DISPLAYTEXT) | |
| BSSL_NAMESPACE_END | |
| #endif // OPENSSL_HEADER_CRYPTO_ASN1_INTERNAL_H |