diff --git a/src/der-builder.c b/src/der-builder.c index 30df7e4..e7f52cc 100644 --- a/src/der-builder.c +++ b/src/der-builder.c @@ -1,647 +1,667 @@ /* der-builder.c - Straightforward DER object builder * Copyright (C) 2020 g10 Code GmbH * * This file is part of KSBA. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1-or-later */ /* This is a new way in KSBA to build DER objects without the need and * overhead of using an ASN.1 module. It further avoids a lot of error * checking because the error checking is delayed to the last call. * * For an example on how to use it see cms.c */ #include #include #include #include #include #include "util.h" #include "asn1-constants.h" #include "convert.h" #include "ber-help.h" #include "der-builder.h" struct item_s { unsigned int tag; - short int class; - unsigned int hdrlen:12; /* Computed size of tag+length field. */ + unsigned int class:2; + unsigned int hdrlen:10; /* Computed size of tag+length field. */ unsigned int is_constructed:1; /* This is a constructed element. */ + unsigned int encapsulate:1; /* This encapsulates other objects. */ unsigned int verbatim:1; /* Copy the value verbatim. */ unsigned int is_stop:1; /* This is a STOP item. */ const void *value; size_t valuelen; char *buffer; /* Malloced space or NULL. */ }; /* Our DER context object; it may eventually be extended to also * feature a parser. */ struct ksba_der_s { gpg_error_t error; /* Last error. */ size_t nallocateditems; /* Number of allocated items. */ size_t nitems; /* Number of used items. */ struct item_s *items; /* Array of items. */ int laststop; /* Used as return value of compute_length. */ unsigned int finished:1;/* The object has been constructed. */ }; /* Release a DER object. */ void _ksba_der_release (ksba_der_t d) { int idx; if (!d) return; for (idx=0; idx < d->nitems; idx++) xfree (d->items[idx].buffer); xfree (d->items); xfree (d); } /* Allocate a new DER builder instance. Returns NULL on error. * NITEMS can be used to tell the number of DER items needed so to * reduce the number of automatic reallocations. */ ksba_der_t _ksba_der_builder_new (unsigned int nitems) { ksba_der_t d; d = xtrycalloc (1, sizeof *d); if (!d) return NULL; if (nitems) { d->nallocateditems = nitems; d->items = xtrycalloc (d->nallocateditems, sizeof *d->items); if (!d->items) { xfree (d); return NULL; } } return d; } /* Reset a DER build context so that a new sequence can be build. */ void _ksba_der_builder_reset (ksba_der_t d) { int idx; if (!d) return; /* Oops. */ for (idx=0; idx < d->nitems; idx++) { if (d->items[idx].buffer) { xfree (d->items[idx].buffer); d->items[idx].buffer = NULL; } d->items[idx].hdrlen = 0; d->items[idx].is_constructed = 0; + d->items[idx].encapsulate = 0; d->items[idx].verbatim = 0; d->items[idx].is_stop = 0; d->items[idx].value = NULL; } d->nitems = 0; d->finished = 0; d->error = 0; } /* Make sure the array of items is large enough for one new item. * Records any error in D and returns true in that case. True is also * returned if D is in finished state. */ static int ensure_space (ksba_der_t d) { struct item_s *newitems; if (!d || d->error || d->finished) return 1; if (d->nitems == d->nallocateditems) { d->nallocateditems += 32; newitems = _ksba_reallocarray (d->items, d->nitems, d->nallocateditems, sizeof *newitems); if (!newitems) d->error = gpg_error_from_syserror (); else d->items = newitems; } return !!d->error; } /* Add a new primitive element to the builder instance D. The element * is described by CLASS, TAG, VALUE, and VALUELEN. CLASS and TAG * must describe a primitive element and (VALUE,VALUELEN) specify its * value. The value is a pointer and its object must not be changed * as long as the instance D exists. For a TYPE_NULL tag no value is * expected. Errors are not returned but recorded for later * retrieval. */ void _ksba_der_add_ptr (ksba_der_t d, int class, int tag, void *value, size_t valuelen) { if (ensure_space (d)) return; - d->items[d->nitems].class = class; + d->items[d->nitems].class = class & 0x03; d->items[d->nitems].tag = tag; d->items[d->nitems].value = value; d->items[d->nitems].valuelen = valuelen; d->nitems++; } /* This is a low level function which assumes that D has been * validated, VALUE is not NULL and enough space for a new item is * available. It takes ownership of VALUE. VERBATIM is usually * passed as false */ static void add_val_core (ksba_der_t d, int class, int tag, void *value, size_t valuelen, int verbatim) { d->items[d->nitems].buffer = value; - d->items[d->nitems].class = class; + d->items[d->nitems].class = class & 0x03; d->items[d->nitems].tag = tag; d->items[d->nitems].value = value; d->items[d->nitems].valuelen = valuelen; d->items[d->nitems].verbatim = !!verbatim; d->nitems++; } /* This is the same as ksba_der_add_ptr but it takes a copy of the * value and thus the caller does not need to care about keeping the * value. */ void _ksba_der_add_val (ksba_der_t d, int class, int tag, const void *value, size_t valuelen) { void *p; if (ensure_space (d)) return; if (!value || !valuelen) { d->error = gpg_error (GPG_ERR_INV_VALUE); return; } p = xtrymalloc (valuelen); if (!p) { d->error = gpg_error_from_syserror (); return; } memcpy (p, value, valuelen); add_val_core (d, class, tag, p, valuelen, 0); } /* Add an OBJECT ID element to D. The OID is given in decimal dotted * format as OIDSTR. */ void _ksba_der_add_oid (ksba_der_t d, const char *oidstr) { gpg_error_t err; unsigned char *buf; size_t len; if (ensure_space (d)) return; err = ksba_oid_from_str (oidstr, &buf, &len); if (err) d->error = err; else add_val_core (d, 0, TYPE_OBJECT_ID, buf, len, 0); } /* Add a BIT STRING to D. Using a separate function allows to easily * pass the number of unused bits. */ void _ksba_der_add_bts (ksba_der_t d, const void *value, size_t valuelen, unsigned int unusedbits) { unsigned char *p; if (ensure_space (d)) return; if (!value || !valuelen || unusedbits > 7) { d->error = gpg_error (GPG_ERR_INV_VALUE); return; } p = xtrymalloc (1+valuelen); if (!p) { d->error = gpg_error_from_syserror (); return; } p[0] = unusedbits; memcpy (p+1, value, valuelen); add_val_core (d, 0, TYPE_BIT_STRING, p, 1+valuelen, 0); } /* Add (VALUE, VALUELEN) as an INTEGER to D. If FORCE_POSITIVE iset * set a 0 or positive number is stored regardless of what is in * (VALUE, VALUELEN). */ void _ksba_der_add_int (ksba_der_t d, const void *value, size_t valuelen, int force_positive) { unsigned char *p; int need_extra; if (ensure_space (d)) return; if (!value || !valuelen) need_extra = 1; /* Assume the integer value 0 was meant. */ else need_extra = (force_positive && (*(const unsigned char*)value & 0x80)); p = xtrymalloc (need_extra+valuelen); if (!p) { d->error = gpg_error_from_syserror (); return; } if (need_extra) p[0] = 0; if (valuelen) memcpy (p+need_extra, value, valuelen); add_val_core (d, 0, TYPE_INTEGER, p, need_extra+valuelen, 0); } /* This function allows to add a pre-constructed DER object to the * builder. It should be a valid DER object but its values is not * further checked and copied verbatim to the final DER object * constructed for the handle D. */ void _ksba_der_add_der (ksba_der_t d, const void *der, size_t derlen) { void *p; if (ensure_space (d)) return; if (!der || !derlen) { d->error = gpg_error (GPG_ERR_INV_VALUE); return; } p = xtrymalloc (derlen); if (!p) { d->error = gpg_error_from_syserror (); return; } memcpy (p, der, derlen); add_val_core (d, 0, 0, p, derlen, 1); } /* Add a new constructed object to the builder instance D. The object * is described by CLASS and TAG which must describe a constructed * object. The elements of the constructed objects are added with * more call using the add functions. To close a constructed element * a call to tlv_builer_add_end is required. Errors are not returned * but recorded for later retrieval. */ void _ksba_der_add_tag (ksba_der_t d, int class, int tag) { if (ensure_space (d)) return; - d->items[d->nitems].class = class; + d->items[d->nitems].class = class & 0x03; d->items[d->nitems].tag = tag; d->items[d->nitems].is_constructed = 1; + d->items[d->nitems].encapsulate = !!(class & 0x80); d->nitems++; } /* A call to this function closes a constructed element. This must be * called even for an empty constructed element. */ void _ksba_der_add_end (ksba_der_t d) { if (ensure_space (d)) return; d->items[d->nitems].is_stop = 1; d->nitems++; } /* Return the length of the TL header of a to be constructed TLV. * LENGTH gives the length of the value, if it is 0 indefinite length * is assumed. LENGTH is ignored for the NULL tag. On error 0 is * returned. Note that this function is similar to _ksba_ber_count_tl * but we want our own copy here. */ static unsigned int count_tl (int class, int tag, size_t length) { unsigned int hdrlen = 0; int i, t; if (tag < 0x1f) hdrlen++; else { hdrlen++; for (i = 0, t = tag; t > 0; i++) t >>= 7; hdrlen += i; } if (!tag && !class) hdrlen++; /* end tag */ else if (tag == TYPE_NULL && !class) hdrlen++; /* NULL tag */ else if (!length) hdrlen++; /* indefinite length */ else if (length < 128) hdrlen++; else { i = (length <= 0xff ? 1: length <= 0xffff ? 2: length <= 0xffffff ? 3: 4); hdrlen++; if (i > 3) hdrlen++; if (i > 2) hdrlen++; if (i > 1) hdrlen++; hdrlen++; } return hdrlen; } /* Write TAG of CLASS to BUFFER. CONSTRUCTED is a flag telling * whether the value is constructed. LENGTH gives the length of the * value, if it is 0 undefinite length is assumed. LENGTH is ignored * for the NULL tag. TAG must be less that 0x1f. The caller must * make sure that the written TL field does not overflow the * buffer. */ static void write_tl (unsigned char *buffer, int class, int tag, int constructed, size_t length) { int i, savei, t; if (tag < 0x1f) { *buffer = (class << 6) | tag; if (constructed) *buffer |= 0x20; buffer++; } else { *buffer = (class << 6) | 0x1f; if (constructed) *buffer |= 0x20; buffer++; for (i = 0, t = tag; t > 0; i++) t >>= 7; savei = i; t = tag; while (i-- > 0) { buffer[i] = t & 0x7f; if (i != savei - 1) buffer[i] |= 0x80; t >>= 7; } buffer += savei; } if (!tag && !class) *buffer++ = 0; /* end tag */ else if (tag == TYPE_NULL && !class) *buffer++ = 0; /* NULL tag */ else if (!length) *buffer++ = 0x80; /* indefinite length */ else if (length < 128) *buffer++ = length; else { /* If we know the sizeof a size_t we could support larger * objects - however this is pretty ridiculous */ i = (length <= 0xff ? 1: length <= 0xffff ? 2: length <= 0xffffff ? 3: 4); *buffer++ = (0x80 | i); if (i > 3) *buffer++ = length >> 24; if (i > 2) *buffer++ = length >> 16; if (i > 1) *buffer++ = length >> 8; *buffer++ = length; } } /* Compute and set the length of all constructed elements in the item * array of D starting at IDX up to the corresponding stop item. On * error d->error is set. */ static size_t compute_lengths (ksba_der_t d, int idx) { size_t total = 0; if (d->error) return 0; for (; idx < d->nitems; idx++) { if (d->items[idx].is_stop) { d->laststop = idx; break; } if (d->items[idx].verbatim) { total += d->items[idx].valuelen; continue; } if (d->items[idx].is_constructed) { d->items[idx].valuelen = compute_lengths (d, idx+1); if (d->error) return 0; /* Note: The last processed IDX is stored at d->LASTSTOP. */ } d->items[idx].hdrlen = count_tl (d->items[idx].class, d->items[idx].tag, d->items[idx].valuelen); if (!d->items[idx].hdrlen) { if (d->error) d->error = gpg_error (GPG_ERR_ENCODING_PROBLEM); return 0; /* Error. */ } total += d->items[idx].hdrlen + d->items[idx].valuelen; if (d->items[idx].is_constructed) - idx = d->laststop; + { + if (d->items[idx].encapsulate && d->items[idx].tag == TYPE_BIT_STRING) + total++; /* Account for the unused bits octet. */ + idx = d->laststop; + } } return total; } /* Return the constructed DER object at D. On success the object is * stored at R_OBJ and its length at R_OBJLEN. The caller needs to * release that memory. On error NULL is stored at R_OBJ and an error * code is returned. Further the number of successful calls prior to * the error are stored at R_OBJLEN. Note than an error may stem from * any of the previous call made to this object or from constructing * the DER object. If this function is called with NULL for R_OBJ * only the current error state is returned and no further processing * is done. This can be used to figure which of the add calls induced * the error. */ gpg_error_t _ksba_der_builder_get (ksba_der_t d, unsigned char **r_obj, size_t *r_objlen) { gpg_error_t err; int idx; unsigned char *buffer = NULL; unsigned char *p; size_t bufsize, buflen; + int encap_bts; *r_obj = NULL; *r_objlen = 0; if (!d) return gpg_error (GPG_ERR_INV_ARG); if (d->error) { err = d->error; if (r_objlen) *r_objlen = d->nitems; goto leave; } if (!r_obj) return 0; if (!d->finished) { if (d->nitems == 1) ; /* Single item does not need an end tag. */ else if (!d->nitems || !d->items[d->nitems-1].is_stop) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } compute_lengths (d, 0); err = d->error; if (err) goto leave; d->finished = 1; } /* If the first element is a primitive element we rightly assume no * other elements follow. It is the user's duty to build a valid * ASN.1 object. */ bufsize = d->items[0].hdrlen + d->items[0].valuelen; /* for (idx=0; idx < d->nitems; idx++) */ /* gpgrt_log_debug ("DERB[%2d]: c=%d t=%2d %s p=%p h=%u l=%zu\n", */ /* idx, */ /* d->items[idx].class, */ /* d->items[idx].tag, */ /* d->items[idx].verbatim? "verbatim": */ /* d->items[idx].is_stop? "stop": */ /* d->items[idx].is_constructed? "cons":"prim", */ /* d->items[idx].value, */ /* d->items[idx].hdrlen, */ /* d->items[idx].valuelen); */ buffer = xtrymalloc (bufsize); if (!buffer) { err = gpg_error_from_syserror (); goto leave; } buflen = 0; p = buffer; for (idx=0; idx < d->nitems; idx++) { if (d->items[idx].is_stop) continue; if (!d->items[idx].verbatim) { - if (buflen + d->items[idx].hdrlen > bufsize) + /* For data encapsulated in a bit string we need to adjust + * for the unused bits octet. */ + encap_bts = (d->items[idx].encapsulate && !d->items[idx].class + && d->items[idx].tag == TYPE_BIT_STRING); + + if (buflen + d->items[idx].hdrlen + encap_bts > bufsize) { err = gpg_error (GPG_ERR_BUG); goto leave; } write_tl (p, d->items[idx].class, d->items[idx].tag, - d->items[idx].is_constructed, d->items[idx].valuelen); + (d->items[idx].is_constructed + && !d->items[idx].encapsulate), + d->items[idx].valuelen + encap_bts); p += d->items[idx].hdrlen; buflen += d->items[idx].hdrlen; + if (encap_bts) + { + *p++ = 0; + buflen++; + } } if (d->items[idx].value) { if (buflen + d->items[idx].valuelen > bufsize) { err = gpg_error (GPG_ERR_BUG); goto leave; } memcpy (p, d->items[idx].value, d->items[idx].valuelen); p += d->items[idx].valuelen; buflen += d->items[idx].valuelen; } } assert (buflen == bufsize); *r_obj = buffer; *r_objlen = buflen; buffer = NULL; leave: xfree (buffer); return err; } diff --git a/src/ksba.h.in b/src/ksba.h.in index a9f08b8..78efc81 100644 --- a/src/ksba.h.in +++ b/src/ksba.h.in @@ -1,636 +1,637 @@ /* ksba.h - X.509 library used by GnuPG * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2010, 2011 * 2012, 2013, 2104, 2015, 2019 g10 Code GmbH * * This file is part of KSBA. * * KSBA is free software; you can redistribute it and/or modify * it under the terms of either * * - the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at * your option) any later version. * * or * * - the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at * your option) any later version. * * or both in parallel, as here. * * KSBA is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * You should have received a copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, see . */ #ifndef KSBA_H #define KSBA_H 1 #include #include #ifdef __cplusplus extern "C" { #if 0 } #endif #endif /* The version of this header should match the one of the library. Do * not use this symbol in your application; use assuan_check_version * instead. */ #define KSBA_VERSION "@VERSION@" /* The version number of this header. It may be used to handle minor * API incompatibilities. */ #define KSBA_VERSION_NUMBER @VERSION_NUMBER@ /* Check for compiler features. */ #ifdef __GNUC__ #define _KSBA_GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #if _KSBA_GCC_VERSION > 30100 #define _KSBA_DEPRECATED __attribute__ ((__deprecated__)) #endif #endif /*__GNUC__*/ #ifndef _KSBA_DEPRECATED #define _KSBA_DEPRECATED #endif #define KSBA_CLASS_UNIVERSAL 0 #define KSBA_CLASS_APPLICATION 1 #define KSBA_CLASS_CONTEXT 2 #define KSBA_CLASS_PRIVATE 3 +#define KSBA_CLASS_ENCAPSULATE 0x80 /* Pseudo class. */ #define KSBA_TYPE_BOOLEAN 1 #define KSBA_TYPE_INTEGER 2 #define KSBA_TYPE_BIT_STRING 3 #define KSBA_TYPE_OCTET_STRING 4 #define KSBA_TYPE_NULL 5 #define KSBA_TYPE_OBJECT_ID 6 #define KSBA_TYPE_OBJECT_DESCRIPTOR 7 #define KSBA_TYPE_EXTERNAL 8 #define KSBA_TYPE_REAL 9 #define KSBA_TYPE_ENUMERATED 10 #define KSBA_TYPE_EMBEDDED_PDV 11 #define KSBA_TYPE_UTF8_STRING 12 #define KSBA_TYPE_RELATIVE_OID 13 #define KSBA_TYPE_TIME 14 #define KSBA_TYPE_SEQUENCE 16 #define KSBA_TYPE_SET 17 #define KSBA_TYPE_NUMERIC_STRING 18 #define KSBA_TYPE_PRINTABLE_STRING 19 #define KSBA_TYPE_TELETEX_STRING 20 #define KSBA_TYPE_VIDEOTEX_STRING 21 #define KSBA_TYPE_IA5_STRING 22 #define KSBA_TYPE_UTC_TIME 23 #define KSBA_TYPE_GENERALIZED_TIME 24 #define KSBA_TYPE_GRAPHIC_STRING 25 #define KSBA_TYPE_VISIBLE_STRING 26 #define KSBA_TYPE_GENERAL_STRING 27 #define KSBA_TYPE_UNIVERSAL_STRING 28 #define KSBA_TYPE_CHARACTER_STRING 29 #define KSBA_TYPE_BMP_STRING 30 #define KSBA_TYPE_DATE 31 #define KSBA_TYPE_TIME_OF_DAY 32 #define KSBA_TYPE_DATE_TIME 33 #define KSBA_TYPE_DURATION 34 #define KSBA_TYPE_OID_IRI 35 #define KSBA_TYPE_RELATIVE_OID_IRI 36 typedef gpg_error_t KsbaError _KSBA_DEPRECATED; typedef enum { KSBA_CT_NONE = 0, KSBA_CT_DATA = 1, KSBA_CT_SIGNED_DATA = 2, KSBA_CT_ENVELOPED_DATA = 3, KSBA_CT_DIGESTED_DATA = 4, KSBA_CT_ENCRYPTED_DATA = 5, KSBA_CT_AUTH_DATA = 6, KSBA_CT_PKCS12 = 7, KSBA_CT_SPC_IND_DATA_CTX = 8 } ksba_content_type_t; typedef ksba_content_type_t KsbaContentType _KSBA_DEPRECATED; typedef enum { KSBA_SR_NONE = 0, /* Never seen by libksba user. */ KSBA_SR_RUNNING = 1, /* Never seen by libksba user. */ KSBA_SR_GOT_CONTENT = 2, KSBA_SR_NEED_HASH = 3, KSBA_SR_BEGIN_DATA = 4, KSBA_SR_END_DATA = 5, KSBA_SR_READY = 6, KSBA_SR_NEED_SIG = 7, KSBA_SR_DETACHED_DATA = 8, KSBA_SR_BEGIN_ITEMS = 9, KSBA_SR_GOT_ITEM = 10, KSBA_SR_END_ITEMS = 11 } ksba_stop_reason_t; typedef ksba_stop_reason_t KsbaStopReason _KSBA_DEPRECATED; typedef enum { KSBA_CRLREASON_UNSPECIFIED = 1, KSBA_CRLREASON_KEY_COMPROMISE = 2, KSBA_CRLREASON_CA_COMPROMISE = 4, KSBA_CRLREASON_AFFILIATION_CHANGED = 8, KSBA_CRLREASON_SUPERSEDED = 16, KSBA_CRLREASON_CESSATION_OF_OPERATION = 32, KSBA_CRLREASON_CERTIFICATE_HOLD = 64, KSBA_CRLREASON_REMOVE_FROM_CRL = 256, KSBA_CRLREASON_PRIVILEGE_WITHDRAWN = 512, KSBA_CRLREASON_AA_COMPROMISE = 1024, KSBA_CRLREASON_OTHER = 32768 } ksba_crl_reason_t; typedef ksba_crl_reason_t KsbaCRLReason _KSBA_DEPRECATED; typedef enum { KSBA_OCSP_RSPSTATUS_SUCCESS = 0, KSBA_OCSP_RSPSTATUS_MALFORMED = 1, KSBA_OCSP_RSPSTATUS_INTERNAL = 2, KSBA_OCSP_RSPSTATUS_TRYLATER = 3, KSBA_OCSP_RSPSTATUS_SIGREQUIRED = 5, KSBA_OCSP_RSPSTATUS_UNAUTHORIZED = 6, KSBA_OCSP_RSPSTATUS_REPLAYED = 253, KSBA_OCSP_RSPSTATUS_OTHER = 254, KSBA_OCSP_RSPSTATUS_NONE = 255 } ksba_ocsp_response_status_t; typedef enum { KSBA_STATUS_NONE = 0, KSBA_STATUS_UNKNOWN = 1, KSBA_STATUS_GOOD = 2, KSBA_STATUS_REVOKED = 4 } ksba_status_t; typedef enum { KSBA_KEYUSAGE_DIGITAL_SIGNATURE = 1, KSBA_KEYUSAGE_NON_REPUDIATION = 2, KSBA_KEYUSAGE_KEY_ENCIPHERMENT = 4, KSBA_KEYUSAGE_DATA_ENCIPHERMENT = 8, KSBA_KEYUSAGE_KEY_AGREEMENT = 16, KSBA_KEYUSAGE_KEY_CERT_SIGN = 32, KSBA_KEYUSAGE_CRL_SIGN = 64, KSBA_KEYUSAGE_ENCIPHER_ONLY = 128, KSBA_KEYUSAGE_DECIPHER_ONLY = 256 } ksba_key_usage_t; typedef ksba_key_usage_t KsbaKeyUsage _KSBA_DEPRECATED; /* ISO format, e.g. "19610711T172059", assumed to be UTC. */ typedef char ksba_isotime_t[16]; /* X.509 certificates are represented by this object. ksba_cert_new() creates such an object */ struct ksba_cert_s; typedef struct ksba_cert_s *ksba_cert_t; typedef struct ksba_cert_s *KsbaCert _KSBA_DEPRECATED; /* CMS objects are controlled by this object. ksba_cms_new() creates it */ struct ksba_cms_s; typedef struct ksba_cms_s *ksba_cms_t; typedef struct ksba_cms_s *KsbaCMS _KSBA_DEPRECATED; /* CRL objects are controlled by this object. ksba_crl_new() creates it */ struct ksba_crl_s; typedef struct ksba_crl_s *ksba_crl_t; typedef struct ksba_crl_s *KsbaCRL _KSBA_DEPRECATED; /* OCSP objects are controlled by this object. ksba_ocsp_new() creates it. */ struct ksba_ocsp_s; typedef struct ksba_ocsp_s *ksba_ocsp_t; /* PKCS-10 creation is controlled by this object. ksba_certreq_new() creates it */ struct ksba_certreq_s; typedef struct ksba_certreq_s *ksba_certreq_t; typedef struct ksba_certreq_s *KsbaCertreq _KSBA_DEPRECATED; /* This is a reader object for various purposes see ksba_reader_new et al. */ struct ksba_reader_s; typedef struct ksba_reader_s *ksba_reader_t; typedef struct ksba_reader_s *KsbaReader _KSBA_DEPRECATED; /* This is a writer object for various purposes see ksba_writer_new et al. */ struct ksba_writer_s; typedef struct ksba_writer_s *ksba_writer_t; typedef struct ksba_writer_s *KsbaWriter _KSBA_DEPRECATED; /* This is an object to store an ASN.1 parse tree as create by ksba_asn_parse_file() */ struct ksba_asn_tree_s; typedef struct ksba_asn_tree_s *ksba_asn_tree_t; typedef struct ksba_asn_tree_s *KsbaAsnTree _KSBA_DEPRECATED; /* This is an object to reference a General Name. Such an object is returned by several functions. */ struct ksba_name_s; typedef struct ksba_name_s *ksba_name_t; typedef struct ksba_name_s *KsbaName _KSBA_DEPRECATED; /* KsbaSexp is just an unsigned char * which should be used for documentation purpose. The S-expressions returned by libksba are always in canonical representation with an extra 0 byte at the end, so that one can print the values in the debugger and at least see the first bytes */ typedef unsigned char *ksba_sexp_t; typedef unsigned char *KsbaSexp _KSBA_DEPRECATED; typedef const unsigned char *ksba_const_sexp_t; typedef const unsigned char *KsbaConstSexp _KSBA_DEPRECATED; /* This is a generic object used by various functions. */ struct ksba_der_s; typedef struct ksba_der_s *ksba_der_t; /*-- cert.c --*/ gpg_error_t ksba_cert_new (ksba_cert_t *acert); void ksba_cert_ref (ksba_cert_t cert); void ksba_cert_release (ksba_cert_t cert); gpg_error_t ksba_cert_set_user_data (ksba_cert_t cert, const char *key, const void *data, size_t datalen); gpg_error_t ksba_cert_get_user_data (ksba_cert_t cert, const char *key, void *buffer, size_t bufferlen, size_t *datalen); gpg_error_t ksba_cert_read_der (ksba_cert_t cert, ksba_reader_t reader); gpg_error_t ksba_cert_init_from_mem (ksba_cert_t cert, const void *buffer, size_t length); const unsigned char *ksba_cert_get_image (ksba_cert_t cert, size_t *r_length); gpg_error_t ksba_cert_hash (ksba_cert_t cert, int what, void (*hasher)(void *, const void *, size_t length), void *hasher_arg); const char *ksba_cert_get_digest_algo (ksba_cert_t cert); ksba_sexp_t ksba_cert_get_serial (ksba_cert_t cert); char *ksba_cert_get_issuer (ksba_cert_t cert, int idx); gpg_error_t ksba_cert_get_validity (ksba_cert_t cert, int what, ksba_isotime_t r_time); char *ksba_cert_get_subject (ksba_cert_t cert, int idx); ksba_sexp_t ksba_cert_get_public_key (ksba_cert_t cert); ksba_sexp_t ksba_cert_get_sig_val (ksba_cert_t cert); gpg_error_t ksba_cert_get_extension (ksba_cert_t cert, int idx, char const **r_oid, int *r_crit, size_t *r_deroff, size_t *r_derlen); gpg_error_t ksba_cert_is_ca (ksba_cert_t cert, int *r_ca, int *r_pathlen); gpg_error_t ksba_cert_get_key_usage (ksba_cert_t cert, unsigned int *r_flags); gpg_error_t ksba_cert_get_cert_policies (ksba_cert_t cert, char **r_policies); gpg_error_t ksba_cert_get_ext_key_usages (ksba_cert_t cert, char **result); gpg_error_t ksba_cert_get_crl_dist_point (ksba_cert_t cert, int idx, ksba_name_t *r_distpoint, ksba_name_t *r_issuer, ksba_crl_reason_t *r_reason); gpg_error_t ksba_cert_get_auth_key_id (ksba_cert_t cert, ksba_sexp_t *r_keyid, ksba_name_t *r_name, ksba_sexp_t *r_serial); gpg_error_t ksba_cert_get_subj_key_id (ksba_cert_t cert, int *r_crit, ksba_sexp_t *r_keyid); gpg_error_t ksba_cert_get_authority_info_access (ksba_cert_t cert, int idx, char **r_method, ksba_name_t *r_location); gpg_error_t ksba_cert_get_subject_info_access (ksba_cert_t cert, int idx, char **r_method, ksba_name_t *r_location); /*-- cms.c --*/ ksba_content_type_t ksba_cms_identify (ksba_reader_t reader); gpg_error_t ksba_cms_new (ksba_cms_t *r_cms); void ksba_cms_release (ksba_cms_t cms); gpg_error_t ksba_cms_set_reader_writer (ksba_cms_t cms, ksba_reader_t r, ksba_writer_t w); gpg_error_t ksba_cms_parse (ksba_cms_t cms, ksba_stop_reason_t *r_stopreason); gpg_error_t ksba_cms_build (ksba_cms_t cms, ksba_stop_reason_t *r_stopreason); ksba_content_type_t ksba_cms_get_content_type (ksba_cms_t cms, int what); const char *ksba_cms_get_content_oid (ksba_cms_t cms, int what); gpg_error_t ksba_cms_get_content_enc_iv (ksba_cms_t cms, void *iv, size_t maxivlen, size_t *ivlen); const char *ksba_cms_get_digest_algo_list (ksba_cms_t cms, int idx); gpg_error_t ksba_cms_get_issuer_serial (ksba_cms_t cms, int idx, char **r_issuer, ksba_sexp_t *r_serial); const char *ksba_cms_get_digest_algo (ksba_cms_t cms, int idx); ksba_cert_t ksba_cms_get_cert (ksba_cms_t cms, int idx); gpg_error_t ksba_cms_get_message_digest (ksba_cms_t cms, int idx, char **r_digest, size_t *r_digest_len); gpg_error_t ksba_cms_get_signing_time (ksba_cms_t cms, int idx, ksba_isotime_t r_sigtime); gpg_error_t ksba_cms_get_sigattr_oids (ksba_cms_t cms, int idx, const char *reqoid, char **r_value); ksba_sexp_t ksba_cms_get_sig_val (ksba_cms_t cms, int idx); ksba_sexp_t ksba_cms_get_enc_val (ksba_cms_t cms, int idx); void ksba_cms_set_hash_function (ksba_cms_t cms, void (*hash_fnc)(void *, const void *, size_t), void *hash_fnc_arg); gpg_error_t ksba_cms_hash_signed_attrs (ksba_cms_t cms, int idx); gpg_error_t ksba_cms_set_content_type (ksba_cms_t cms, int what, ksba_content_type_t type); gpg_error_t ksba_cms_add_digest_algo (ksba_cms_t cms, const char *oid); gpg_error_t ksba_cms_add_signer (ksba_cms_t cms, ksba_cert_t cert); gpg_error_t ksba_cms_add_cert (ksba_cms_t cms, ksba_cert_t cert); gpg_error_t ksba_cms_add_smime_capability (ksba_cms_t cms, const char *oid, const unsigned char *der, size_t derlen); gpg_error_t ksba_cms_set_message_digest (ksba_cms_t cms, int idx, const unsigned char *digest, size_t digest_len); gpg_error_t ksba_cms_set_signing_time (ksba_cms_t cms, int idx, const ksba_isotime_t sigtime); gpg_error_t ksba_cms_set_sig_val (ksba_cms_t cms, int idx, ksba_const_sexp_t sigval); gpg_error_t ksba_cms_set_content_enc_algo (ksba_cms_t cms, const char *oid, const void *iv, size_t ivlen); gpg_error_t ksba_cms_add_recipient (ksba_cms_t cms, ksba_cert_t cert); gpg_error_t ksba_cms_set_enc_val (ksba_cms_t cms, int idx, ksba_const_sexp_t encval); /*-- crl.c --*/ gpg_error_t ksba_crl_new (ksba_crl_t *r_crl); void ksba_crl_release (ksba_crl_t crl); gpg_error_t ksba_crl_set_reader (ksba_crl_t crl, ksba_reader_t r); void ksba_crl_set_hash_function (ksba_crl_t crl, void (*hash_fnc)(void *, const void *, size_t), void *hash_fnc_arg); const char *ksba_crl_get_digest_algo (ksba_crl_t crl); gpg_error_t ksba_crl_get_issuer (ksba_crl_t crl, char **r_issuer); gpg_error_t ksba_crl_get_extension (ksba_crl_t crl, int idx, char const **oid, int *critical, unsigned char const **der, size_t *derlen); gpg_error_t ksba_crl_get_auth_key_id (ksba_crl_t crl, ksba_sexp_t *r_keyid, ksba_name_t *r_name, ksba_sexp_t *r_serial); gpg_error_t ksba_crl_get_crl_number (ksba_crl_t crl, ksba_sexp_t *number); gpg_error_t ksba_crl_get_update_times (ksba_crl_t crl, ksba_isotime_t this_update, ksba_isotime_t next_update); gpg_error_t ksba_crl_get_item (ksba_crl_t crl, ksba_sexp_t *r_serial, ksba_isotime_t r_revocation_date, ksba_crl_reason_t *r_reason); ksba_sexp_t ksba_crl_get_sig_val (ksba_crl_t crl); gpg_error_t ksba_crl_parse (ksba_crl_t crl, ksba_stop_reason_t *r_stopreason); /*-- ocsp.c --*/ gpg_error_t ksba_ocsp_new (ksba_ocsp_t *r_oscp); void ksba_ocsp_release (ksba_ocsp_t ocsp); gpg_error_t ksba_ocsp_set_digest_algo (ksba_ocsp_t ocsp, const char *oid); gpg_error_t ksba_ocsp_set_requestor (ksba_ocsp_t ocsp, ksba_cert_t cert); gpg_error_t ksba_ocsp_add_target (ksba_ocsp_t ocsp, ksba_cert_t cert, ksba_cert_t issuer_cert); size_t ksba_ocsp_set_nonce (ksba_ocsp_t ocsp, unsigned char *nonce, size_t noncelen); gpg_error_t ksba_ocsp_prepare_request (ksba_ocsp_t ocsp); gpg_error_t ksba_ocsp_hash_request (ksba_ocsp_t ocsp, void (*hasher)(void *, const void *, size_t length), void *hasher_arg); gpg_error_t ksba_ocsp_set_sig_val (ksba_ocsp_t ocsp, ksba_const_sexp_t sigval); gpg_error_t ksba_ocsp_add_cert (ksba_ocsp_t ocsp, ksba_cert_t cert); gpg_error_t ksba_ocsp_build_request (ksba_ocsp_t ocsp, unsigned char **r_buffer, size_t *r_buflen); gpg_error_t ksba_ocsp_parse_response (ksba_ocsp_t ocsp, const unsigned char *msg, size_t msglen, ksba_ocsp_response_status_t *resp_status); const char *ksba_ocsp_get_digest_algo (ksba_ocsp_t ocsp); gpg_error_t ksba_ocsp_hash_response (ksba_ocsp_t ocsp, const unsigned char *msg, size_t msglen, void (*hasher)(void *, const void *, size_t length), void *hasher_arg); ksba_sexp_t ksba_ocsp_get_sig_val (ksba_ocsp_t ocsp, ksba_isotime_t produced_at); gpg_error_t ksba_ocsp_get_responder_id (ksba_ocsp_t ocsp, char **r_name, ksba_sexp_t *r_keyid); ksba_cert_t ksba_ocsp_get_cert (ksba_ocsp_t ocsp, int idx); gpg_error_t ksba_ocsp_get_status (ksba_ocsp_t ocsp, ksba_cert_t cert, ksba_status_t *r_status, ksba_isotime_t r_this_update, ksba_isotime_t r_next_update, ksba_isotime_t r_revocation_time, ksba_crl_reason_t *r_reason); gpg_error_t ksba_ocsp_get_extension (ksba_ocsp_t ocsp, ksba_cert_t cert, int idx, char const **r_oid, int *r_crit, unsigned char const **r_der, size_t *r_derlen); /*-- certreq.c --*/ gpg_error_t ksba_certreq_new (ksba_certreq_t *r_cr); void ksba_certreq_release (ksba_certreq_t cr); gpg_error_t ksba_certreq_set_writer (ksba_certreq_t cr, ksba_writer_t w); void ksba_certreq_set_hash_function ( ksba_certreq_t cr, void (*hash_fnc)(void *, const void *, size_t), void *hash_fnc_arg); gpg_error_t ksba_certreq_add_subject (ksba_certreq_t cr, const char *name); gpg_error_t ksba_certreq_set_public_key (ksba_certreq_t cr, ksba_const_sexp_t key); gpg_error_t ksba_certreq_add_extension (ksba_certreq_t cr, const char *oid, int is_crit, const void *der, size_t derlen); gpg_error_t ksba_certreq_set_sig_val (ksba_certreq_t cr, ksba_const_sexp_t sigval); gpg_error_t ksba_certreq_build (ksba_certreq_t cr, ksba_stop_reason_t *r_stopreason); /* The functions below are used to switch to X.509 certificate creation. */ gpg_error_t ksba_certreq_set_serial (ksba_certreq_t cr, ksba_const_sexp_t sn); gpg_error_t ksba_certreq_set_issuer (ksba_certreq_t cr, const char *name); gpg_error_t ksba_certreq_set_validity (ksba_certreq_t cr, int what, const ksba_isotime_t timebuf); gpg_error_t ksba_certreq_set_siginfo (ksba_certreq_t cr, ksba_const_sexp_t siginfo); /*-- reader.c --*/ gpg_error_t ksba_reader_new (ksba_reader_t *r_r); void ksba_reader_release (ksba_reader_t r); gpg_error_t ksba_reader_set_release_notify (ksba_reader_t r, void (*notify)(void*,ksba_reader_t), void *notify_value); gpg_error_t ksba_reader_clear (ksba_reader_t r, unsigned char **buffer, size_t *buflen); gpg_error_t ksba_reader_error (ksba_reader_t r); gpg_error_t ksba_reader_set_mem (ksba_reader_t r, const void *buffer, size_t length); gpg_error_t ksba_reader_set_fd (ksba_reader_t r, int fd); gpg_error_t ksba_reader_set_file (ksba_reader_t r, FILE *fp); gpg_error_t ksba_reader_set_cb (ksba_reader_t r, int (*cb)(void*,char *,size_t,size_t*), void *cb_value ); gpg_error_t ksba_reader_read (ksba_reader_t r, char *buffer, size_t length, size_t *nread); gpg_error_t ksba_reader_unread (ksba_reader_t r, const void *buffer, size_t count); unsigned long ksba_reader_tell (ksba_reader_t r); /*-- writer.c --*/ gpg_error_t ksba_writer_new (ksba_writer_t *r_w); void ksba_writer_release (ksba_writer_t w); gpg_error_t ksba_writer_set_release_notify (ksba_writer_t w, void (*notify)(void*,ksba_writer_t), void *notify_value); int ksba_writer_error (ksba_writer_t w); unsigned long ksba_writer_tell (ksba_writer_t w); gpg_error_t ksba_writer_set_fd (ksba_writer_t w, int fd); gpg_error_t ksba_writer_set_file (ksba_writer_t w, FILE *fp); gpg_error_t ksba_writer_set_cb (ksba_writer_t w, int (*cb)(void*,const void *,size_t), void *cb_value); gpg_error_t ksba_writer_set_mem (ksba_writer_t w, size_t initial_size); const void *ksba_writer_get_mem (ksba_writer_t w, size_t *nbytes); void * ksba_writer_snatch_mem (ksba_writer_t w, size_t *nbytes); gpg_error_t ksba_writer_set_filter (ksba_writer_t w, gpg_error_t (*filter)(void*, const void *,size_t, size_t *, void *, size_t, size_t *), void *filter_arg); gpg_error_t ksba_writer_write (ksba_writer_t w, const void *buffer, size_t length); gpg_error_t ksba_writer_write_octet_string (ksba_writer_t w, const void *buffer, size_t length, int flush); /*-- asn1-parse.y --*/ int ksba_asn_parse_file (const char *filename, ksba_asn_tree_t *result, int debug); void ksba_asn_tree_release (ksba_asn_tree_t tree); /*-- asn1-func.c --*/ void ksba_asn_tree_dump (ksba_asn_tree_t tree, const char *name, FILE *fp); gpg_error_t ksba_asn_create_tree (const char *mod_name, ksba_asn_tree_t *result); /*-- oid.c --*/ char *ksba_oid_to_str (const char *buffer, size_t length); gpg_error_t ksba_oid_from_str (const char *string, unsigned char **rbuf, size_t *rlength); /*-- dn.c --*/ gpg_error_t ksba_dn_der2str (const void *der, size_t derlen, char **r_string); gpg_error_t ksba_dn_str2der (const char *string, unsigned char **rder, size_t *rderlen); gpg_error_t ksba_dn_teststr (const char *string, int seq, size_t *rerroff, size_t *rerrlen); /*-- name.c --*/ gpg_error_t ksba_name_new (ksba_name_t *r_name); void ksba_name_ref (ksba_name_t name); void ksba_name_release (ksba_name_t name); const char *ksba_name_enum (ksba_name_t name, int idx); char *ksba_name_get_uri (ksba_name_t name, int idx); /*-- der-builder.c --*/ void ksba_der_release (ksba_der_t d); ksba_der_t ksba_der_builder_new (unsigned int nitems); void ksba_der_builder_reset (ksba_der_t d); void ksba_der_add_ptr (ksba_der_t d, int cls, int tag, void *value, size_t valuelen); void ksba_der_add_val (ksba_der_t d, int cls, int tag, const void *value, size_t valuelen); void ksba_der_add_int (ksba_der_t d, const void *value, size_t valuelen, int force_positive); void ksba_der_add_oid (ksba_der_t d, const char *oidstr); void ksba_der_add_bts (ksba_der_t d, const void *value, size_t valuelen, unsigned int unusedbits); void ksba_der_add_der (ksba_der_t d, const void *der, size_t derlen); void ksba_der_add_tag (ksba_der_t d, int cls, int tag); void ksba_der_add_end (ksba_der_t d); gpg_error_t ksba_der_builder_get (ksba_der_t d, unsigned char **r_obj, size_t *r_objlen); /*-- util.c --*/ void ksba_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), void *(*new_realloc_func)(void *p, size_t n), void (*new_free_func)(void*) ); void ksba_set_hash_buffer_function ( gpg_error_t (*fnc) (void *arg, const char *oid, const void *buffer, size_t length, size_t resultsize, unsigned char *result, size_t *resultlen), void *fnc_arg); void *ksba_malloc (size_t n ); void *ksba_calloc (size_t n, size_t m ); void *ksba_realloc (void *p, size_t n); char *ksba_strdup (const char *p); void ksba_free ( void *a ); /*--version.c --*/ const char *ksba_check_version (const char *req_version); #ifdef __cplusplus } #endif #endif /*KSBA_H*/ diff --git a/tests/t-der-builder.c b/tests/t-der-builder.c index e06ff53..05b4d60 100644 --- a/tests/t-der-builder.c +++ b/tests/t-der-builder.c @@ -1,153 +1,202 @@ /* t-der-builder.c - Tests for the DER builder functions * Copyright (C) 2020 g10 Code GmbH * * This file is part of KSBA. * * KSBA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * KSBA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #include "../src/ksba.h" #define PGM "t-der-builder" #include "t-common.h" static int verbose; static void test_der_encoding (void) { gpg_error_t err; ksba_der_t d; unsigned char *der; size_t derlen; d = ksba_der_builder_new (0); if (!d) fail ("error creating new DER builder"); ksba_der_add_ptr (d, KSBA_CLASS_UNIVERSAL, KSBA_TYPE_NULL, NULL, 0); err = ksba_der_builder_get (d, &der, &derlen); fail_if_err (err); if (derlen != 2 || memcmp (der, "\x05\x00", 2)) fail ("bad encoding"); xfree (der); ksba_der_builder_reset (d); ksba_der_add_ptr (d, KSBA_CLASS_UNIVERSAL, KSBA_TYPE_OCTET_STRING, "123", 3); err = ksba_der_builder_get (d, &der, &derlen); fail_if_err (err); if (derlen != 5 || memcmp (der, "\x04\x03""123", 5)) fail ("bad encoding"); xfree (der); ksba_der_builder_reset (d); ksba_der_add_ptr (d, KSBA_CLASS_UNIVERSAL, 65537, "a", 1); err = ksba_der_builder_get (d, &der, &derlen); fail_if_err (err); if (derlen != 6 || memcmp (der, "\x1f\x84\x80\x01\x01\x61", 6)) fail ("bad encoding"); xfree (der); ksba_der_builder_reset (d); ksba_der_add_tag (d, KSBA_CLASS_APPLICATION, 257); err = ksba_der_builder_get (d, &der, &derlen); fail_if_err (err); if (derlen != 4 || memcmp (der, "\x7f\x82\x01\x80", 4)) fail ("bad encoding"); xfree (der); ksba_der_release (d); } static void test_der_builder (void) { gpg_error_t err; ksba_der_t d; unsigned char *der; size_t derlen; d = ksba_der_builder_new (0); if (!d) fail ("error creating new DER builder"); ksba_der_add_tag (d, KSBA_CLASS_UNIVERSAL, KSBA_TYPE_SEQUENCE); ksba_der_add_oid (d, "1.2.3.4"); ksba_der_add_tag (d, KSBA_CLASS_UNIVERSAL, KSBA_TYPE_SET); ksba_der_add_tag (d, KSBA_CLASS_CONTEXT, 0); ksba_der_add_int (d, "\x01", 1, 0); ksba_der_add_end (d); ksba_der_add_tag (d, KSBA_CLASS_CONTEXT, 42); ksba_der_add_int (d, "\x7f", 1, 0); /* 127 */ ksba_der_add_int (d, "\x7f", 1, 1); /* Also 127 */ ksba_der_add_int (d, "\x82", 1, 0); /* Note: this is a negative number. */ ksba_der_add_int (d, "\x83", 1, 1); /* Forces positive encoding. */ ksba_der_add_end (d); ksba_der_add_end (d); err = ksba_der_builder_get (d, &der, &derlen); fail_if_err (err); /* gpgrt_log_printhex (der, derlen, "DER:"); */ if (derlen != 30 || memcmp (der, ("\x30\x1c\x06\x03\x2a\x03\x04\x31\x15\xa0\x03\x02" "\x01\x01\xbf\x2a\x0d\x02\x01\x7f\x02\x01\x7f\x02" "\x01\x82\x02\x02\x00\x83"), 30)) fail ("bad encoding"); xfree (der); + + /* Now test our encapsulate feature. */ + ksba_der_builder_reset (d); + + ksba_der_add_tag (d, KSBA_CLASS_UNIVERSAL, KSBA_TYPE_SEQUENCE); + ksba_der_add_oid (d, "1.2.3.4"); + ksba_der_add_tag (d, KSBA_CLASS_ENCAPSULATE, KSBA_TYPE_OCTET_STRING); + ksba_der_add_tag (d, KSBA_CLASS_UNIVERSAL, KSBA_TYPE_SEQUENCE); + ksba_der_add_int (d, "\x01\xc3", 2, 0); /* Integer 451 */ + ksba_der_add_tag (d, KSBA_CLASS_CONTEXT, 0); /* [0] */ + ksba_der_add_int (d, "\x2a", 1, 0); /* Integer 42 */ + ksba_der_add_end (d); /* End [0] */ + ksba_der_add_end (d); /* End sequence */ + ksba_der_add_end (d); /* End octet string */ + ksba_der_add_end (d); /* End sequence */ + + err = ksba_der_builder_get (d, &der, &derlen); + fail_if_err (err); + if (derlen != 20 + || memcmp (der, ("\x30\x12\x06\x03\x2a\x03\x04\x04\x0b\x30" + "\x09\x02\x02\x01\xc3\xa0\x03\x02\x01\x2a"), 20)) + fail ("bad encoding"); + xfree (der); + + /* Encapsulate in a bit string. */ + ksba_der_builder_reset (d); + + ksba_der_add_tag (d, KSBA_CLASS_UNIVERSAL, KSBA_TYPE_SEQUENCE); + ksba_der_add_oid (d, "1.2.3.4"); + ksba_der_add_tag (d, KSBA_CLASS_ENCAPSULATE, KSBA_TYPE_BIT_STRING); + ksba_der_add_tag (d, KSBA_CLASS_UNIVERSAL, KSBA_TYPE_SEQUENCE); + ksba_der_add_int (d, "\x01\xc3", 2, 0); /* Integer 451 */ + ksba_der_add_tag (d, KSBA_CLASS_CONTEXT, 0); /* [0] */ + ksba_der_add_int (d, "\x2a", 1, 0); /* Integer 42 */ + ksba_der_add_end (d); /* End [0] */ + ksba_der_add_end (d); /* End sequence */ + ksba_der_add_end (d); /* End octet string */ + ksba_der_add_end (d); /* End sequence */ + + err = ksba_der_builder_get (d, &der, &derlen); + fail_if_err (err); + /* gpgrt_log_printhex (der, derlen, "der:"); */ + if (derlen != 21 + || memcmp (der, ("\x30\x13\x06\x03\x2a\x03\x04\x03\x0c\x00\x30" + "\x09\x02\x02\x01\xc3\xa0\x03\x02\x01\x2a"), 21)) + fail ("bad encoding"); + xfree (der); + + ksba_der_release (d); } int main (int argc, char **argv) { if (argc) { argc--; argv++; } if (argc && !strcmp (*argv, "--verbose")) { verbose = 1; argc--; argv++; } if (!argc) { test_der_encoding (); test_der_builder (); } else { fputs ("usage: "PGM"\n", stderr); return 1; } return 0; }