ASN1_item_d2i
,
ASN1_item_d2i_bio
,
ASN1_item_d2i_fp
,
d2i_ASN1_TYPE
, ASN1_item_i2d
,
ASN1_item_i2d_bio
,
ASN1_item_i2d_fp
,
ASN1_item_ndef_i2d
,
i2d_ASN1_TYPE
, ASN1_item_dup
,
ASN1_item_print
—
decode and encode ASN.1 objects
#include <openssl/asn1.h>
ASN1_VALUE *
ASN1_item_d2i
(ASN1_VALUE
**val_out, const unsigned char **der_in,
long length, const ASN1_ITEM
*it);
void *
ASN1_item_d2i_bio
(const ASN1_ITEM
*it, BIO *in_bio, void
*val_out);
void *
ASN1_item_d2i_fp
(const ASN1_ITEM
*it, FILE *in_fp, void
*val_out);
ASN1_TYPE *
d2i_ASN1_TYPE
(ASN1_TYPE
**val_out, const unsigned char **der_in,
long length);
int
ASN1_item_i2d
(ASN1_VALUE
*val_in, unsigned char **der_out,
const ASN1_ITEM *it);
int
ASN1_item_i2d_bio
(const ASN1_ITEM
*it, BIO *out_bio, void
*val_in);
int
ASN1_item_i2d_fp
(const ASN1_ITEM
*it, FILE *out_fp, void
*val_in);
int
ASN1_item_ndef_i2d
(ASN1_VALUE
*val_in, unsigned char **der_out,
const ASN1_ITEM *it);
int
i2d_ASN1_TYPE
(ASN1_TYPE *val_in,
unsigned char **der_out);
void *
ASN1_item_dup
(const ASN1_ITEM
*it, void *val_in);
int
ASN1_item_print
(BIO *out_bio,
ASN1_VALUE *val_in, int indent,
const ASN1_ITEM *it, const ASN1_PCTX
*pctx);
These functions convert ASN.1 values from their BER encoding to internal C
structures (“d2i”) and vice versa (“i2d”). Unlike
the C structures which contain pointers to sub-objects, BER is a serialized
encoding, suitable for transfer over the network and for storage in a file.
ASN1_item_d2i
() interprets
*der_in as a DER- or BER-encoded byte array and
decodes one value of type it represented by up to
length bytes. If successful,
*der_in is advanced to the byte following the parsed
data.
If decoding succeeds and val_out or
*val_out is NULL
, a new object
is allocated.
If decoding succeeds and *val_out is not
NULL
, it is assumed to point to a valid populated
object and an attempt is made to reuse it. It must not be an empty structure
such as one returned by
ASN1_item_new(3)
or by one of the various type-specific *_new
()
functions. This “reuse” capability is present for backward
compatibility, but its use is strongly discouraged; see the
BUGS section below.
ASN1_item_d2i_bio
() and
ASN1_item_d2i_fp
() are similar to
ASN1_item_d2i
() except that they read from a
BIO or FILE, respectively.
d2i_ASN1_TYPE
() is similar to
ASN1_item_d2i
() except that it does not require a
desired type to be specified by the user, but instead returns an
ASN1_TYPE wrapper object containing both the type and
the value found in the input.
ASN1_item_i2d
() encodes the object pointed
to by val_in into DER format.
If *der_out is not
NULL
, it writes the DER-encoded data to the buffer
at *der_out and increments it to point after the data
just written. In this case, it is the responsibility of the user to make
sure that the buffer pointed to by *der_out is long
enough, such that no buffer overflow can occur.
If *der_out is NULL
,
memory is allocated for a buffer, and *der_out is not
incremented, but points to the start of the data just written.
If der_out is NULL
,
the encoded bytes are not written anywhere but discarded. For
val_in objects of variable encoding size, this is
sometimes used to first find the number of bytes that will be written. Then,
a sufficient amount of memory is allocated before calling
ASN1_item_i2d
() again. This explicit double-call
technique is often not needed because the auto-allocation technique
described in the previous paragraph can be used.
ASN1_item_i2d_bio
() and
ASN1_item_i2d_fp
() are similar to
ASN1_item_i2d
() except that they write to a
BIO or FILE, respectively.
ASN1_item_ndef_i2d
() is similar to
ASN1_item_i2d
() except that it encodes using BER
rather than DER, using the indefinite length form where appropriate.
i2d_ASN1_TYPE
() is similar to
ASN1_item_i2d
() except that the type and the value
are not provided separately, but in the form of a single
ASN1_TYPE object.
ASN1_item_dup
() creates a deep copy of
val_in by calling
ASN1_item_i2d
() and
ASN1_item_d2i
().
If successful, ASN1_item_d2i
(),
ASN1_item_d2i_bio
(),
ASN1_item_d2i_fp
(), and
d2i_ASN1_TYPE
() return a pointer to the decoded ASN.1
value. In addition, if val_out is not
NULL
, the pointer is also written to
*val_out. If an error occurs,
NULL
is returned.
ASN1_item_i2d
(),
ASN1_item_ndef_i2d
(), and
i2d_ASN1_TYPE
() return the number of bytes written
or a negative value if an error occurs.
ASN1_item_i2d_bio
() and
ASN1_item_i2d_fp
() return 1 for success or 0 for
failure.
ASN1_item_dup
() returns the new
ASN1_VALUE object or NULL
if
an error occurs.
Many type-specific wrapper functions exist. Using those wrappers is recommended
in application code because it restores part of the type safety that the
low-level interfaces using ASN1_VALUE lack.
For example, to allocate a buffer and write the DER encoding of an
X509 object into it:
X509 *x;
unsigned char *buf;
int len;
buf = NULL;
len = i2d_X509(x, &buf);
if (len < 0)
/* error */
Attempt to decode a buffer:
X509 *x;
unsigned char *buf;
const unsigned char *p;
int len;
/* Set up buf and len to point to the input buffer. */
p = buf;
x = d2i_X509(NULL, &p, len);
if (x == NULL)
/* error */
Equivalent technique:
X509 *x;
unsigned char *buf;
const unsigned char *p;
int len;
/* Set up buf and len to point to the input buffer. */
p = buf;
x = NULL;
if (d2i_X509(&x, &p, len) == NULL)
/* error */
d2i_ASN1_TYPE
() and
i2d_ASN1_TYPE
() first appeared in SSLeay 0.5.1 and
have been available since OpenBSD 2.4.
ASN1_item_d2i
(),
ASN1_item_d2i_bio
(),
ASN1_item_d2i_fp
(),
ASN1_item_i2d
(),
ASN1_item_i2d_bio
(),
ASN1_item_i2d_fp
(), and
ASN1_item_dup
() first appeared in OpenSSL 0.9.7 and
have been available since OpenBSD 3.2.
ASN1_item_ndef_i2d
() first appeared in
OpenSSL 0.9.8 and has been available since OpenBSD
4.5.
ASN1_item_print
() first appeared in
OpenSSL 1.0.0 and has been available since OpenBSD
4.9.
If the type described by it fails to match the true type
of val_in or *val_out, buffer
overflows and segmentation faults are likely to occur. For more details about
why the type ASN1_VALUE constitutes dangerous user
interface design, see
ASN1_item_new(3).
The encoded data is in binary form and may contain embedded NUL
bytes. Functions such as
strlen(3)
will not return the correct length of the encoded data.
While the way that *der_in and
*der_out are incremented after the operation supports
the typical usage patterns of reading or writing one object after another,
this behaviour can trap the unwary.
Using a temporary pointer into the buffer is mandatory. A common
mistake is to attempt to use a buffer directly as follows:
X509 *x;
unsigned char *buf;
int len;
len = i2d_X509(x, NULL);
buf = malloc(len);
i2d_X509(x, &buf);
/* do something with buf[] */
free(buf);
This code will result in buf apparently
containing garbage because it was incremented during
i2d_X509
() to point after the data just written.
Also buf will no longer contain the pointer allocated
by
malloc(3)
and the subsequent call to
free(3)
is likely to crash.
Another trap to avoid is misuse of the
val_out argument:
X509 *x;
if (d2i_X509(&x, &p, len) == NULL)
/* error */
This will probably crash somewhere in
d2i_X509
() because x is
uninitialized and an attempt will be made to interpret its invalid content
as an X509 object, typically causing a segmentation
violation. If x is set to NULL
first, then this will not happen.
If the “reuse” capability is used, a valid object is passed in via
*val_out, and an error occurs, then the object is not
freed and may be left in an invalid or inconsistent state.
In some versions of OpenSSL, the “reuse” behaviour
is broken such that some parts of the reused object may persist if they are
not present in the new one.
In many versions of OpenSSL,
ASN1_item_i2d
() will not return an error if
mandatory fields are not initialized due to a programming error. In that
case, the encoded structure may contain invalid data and some fields may be
missing entirely, such that trying to parse it with
ASN1_item_d2i
() may fail.
Any function which encodes an object may return a stale encoding
if the object has been modified after deserialization or previous
serialization. This is because some objects cache the encoding for
efficiency reasons.