const char *p;
unsigned non_ascii = 0, i;
- if ((type == GNUTLS_SAN_DNSNAME
+ if ((type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_OTHERNAME_XMPP
|| type == GNUTLS_SAN_RFC822NAME
|| type == GNUTLS_SAN_URI) && sname != NULL && strlen(sname) != name->size) {
adds(str,
case GNUTLS_SAN_DN:
addf(str, _("%sdirectoryName: %.*s\n"), prefix, name->size, NON_NULL(name->data));
break;
+
+ case GNUTLS_SAN_OTHERNAME_XMPP:
+ addf(str, _("%sXMPP: %.*s\n"), prefix, name->size, NON_NULL(name->data));
+ break;
default:
addf(str, _("%sUnknown name: "), prefix);
_gnutls_buffer_hexprint(str, name->data, name->size);
}
}
-static void print_proxy(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
+static void print_proxy(gnutls_buffer_st * str, gnutls_datum_t *der)
{
int pathlen;
char *policyLanguage;
size_t npolicy;
int err;
- err = gnutls_x509_crt_get_proxy(cert, NULL,
- &pathlen, &policyLanguage,
+ err = gnutls_x509_ext_import_proxy(der, &pathlen, &policyLanguage,
&policy, &npolicy);
if (err < 0) {
addf(str, "error: get_proxy: %s\n", gnutls_strerror(err));
_gnutls_buffer_hexprint(str, policy, npolicy);
adds(str, "\n");
}
+ gnutls_free(policy);
+ gnutls_free(policyLanguage);
}
-static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt_t cert)
+static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_datum_t *der)
{
gnutls_x509_name_constraints_t nc;
int ret;
- unsigned critical, idx = 0;
+ unsigned idx = 0;
gnutls_datum_t name;
unsigned type;
char new_prefix[16];
if (ret < 0)
return;
- ret = gnutls_x509_crt_get_name_constraints(cert, nc, 0, &critical);
+ ret = gnutls_x509_ext_import_name_constraints(der, nc, 0);
if (ret < 0)
goto cleanup;
gnutls_x509_aia_deinit(aia);
}
-static void print_ski(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
+static void print_ski(gnutls_buffer_st * str, gnutls_datum_t *der)
{
- char *buffer = NULL;
- size_t size = 0;
+ gnutls_datum_t id = {NULL, 0};
int err;
- err =
- gnutls_x509_crt_get_subject_key_id(cert, buffer, &size, NULL);
- if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
- addf(str, "error: get_subject_key_id: %s\n",
- gnutls_strerror(err));
- return;
- }
-
- buffer = gnutls_malloc(size);
- if (!buffer) {
- addf(str, "error: malloc: %s\n",
- gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
- return;
- }
-
- err =
- gnutls_x509_crt_get_subject_key_id(cert, buffer, &size, NULL);
+ err = gnutls_x509_ext_import_subject_key_id(der, &id);
if (err < 0) {
- gnutls_free(buffer);
- addf(str, "error: get_subject_key_id2: %s\n",
+ addf(str, "error: get_subject_key_id: %s\n",
gnutls_strerror(err));
return;
}
adds(str, "\t\t\t");
- _gnutls_buffer_hexprint(str, buffer, size);
+ _gnutls_buffer_hexprint(str, id.data, id.size);
adds(str, "\n");
- gnutls_free(buffer);
+ gnutls_free(id.data);
}
-#define TYPE_CRL 1
#define TYPE_CRT 2
#define TYPE_CRQ 3
-#define TYPE_PUBKEY 4
-
-#define TYPE_CRT_SAN TYPE_CRT
-#define TYPE_CRQ_SAN TYPE_CRQ
-#define TYPE_CRT_IAN 4
typedef union {
gnutls_x509_crt_t crt;
gnutls_x509_crq_t crq;
- gnutls_x509_crl_t crl;
- gnutls_pubkey_t pubkey;
} cert_type_t;
static void
-print_aki_gn_serial(gnutls_buffer_st * str, int type, cert_type_t cert)
+print_aki_gn_serial(gnutls_buffer_st * str, gnutls_x509_aki_t aki)
{
- char *buffer = NULL;
- char serial[128];
- size_t size = 0, serial_size = sizeof(serial);
+ gnutls_datum_t san, other_oid, serial;
unsigned int alt_type;
- gnutls_datum_t t;
int err;
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_authority_key_gn_serial(cert.crt,
- 0, NULL,
- &size,
- &alt_type,
- serial,
- &serial_size,
- NULL);
- else if (type == TYPE_CRL)
- err =
- gnutls_x509_crl_get_authority_key_gn_serial(cert.crl,
- 0, NULL,
- &size,
- &alt_type,
- serial,
- &serial_size,
- NULL);
- else {
- gnutls_assert();
- return;
- }
-
- if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
- addf(str, "error: get_authority_key_gn_serial: %s\n",
- gnutls_strerror(err));
- return;
- }
-
- buffer = gnutls_malloc(size);
- if (!buffer) {
- addf(str, "error: malloc: %s\n",
- gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
- return;
- }
-
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_authority_key_gn_serial(cert.crt,
- 0, buffer,
- &size,
- &alt_type,
- serial,
- &serial_size,
- NULL);
- else
- err =
- gnutls_x509_crl_get_authority_key_gn_serial(cert.crl,
- 0, buffer,
- &size,
- &alt_type,
- serial,
- &serial_size,
- NULL);
-
+ err =
+ gnutls_x509_aki_get_cert_issuer(aki,
+ 0, &alt_type, &san, &other_oid, &serial);
if (err < 0) {
- gnutls_free(buffer);
- addf(str, "error: get_authority_key_gn_serial2: %s\n",
+ addf(str, "error: gnutls_x509_aki_get_cert_issuer: %s\n",
gnutls_strerror(err));
return;
}
- t.data = (void*)buffer;
- t.size = size;
- print_name(str, "\t\t\t", alt_type, &t);
+ print_name(str, "\t\t\t", alt_type, &san);
adds(str, "\t\t\tserial: ");
- _gnutls_buffer_hexprint(str, serial, serial_size);
+ _gnutls_buffer_hexprint(str, serial.data, serial.size);
adds(str, "\n");
-
- gnutls_free(buffer);
}
-static void print_aki(gnutls_buffer_st * str, int type, cert_type_t cert)
+static void print_aki(gnutls_buffer_st * str, gnutls_datum_t *der)
{
- char *buffer = NULL;
- size_t size = 0;
int err;
+ gnutls_x509_aki_t aki;
+ gnutls_datum_t id;
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_authority_key_id(cert.crt, buffer,
- &size, NULL);
- else if (type == TYPE_CRL)
- err =
- gnutls_x509_crl_get_authority_key_id(cert.crl, buffer,
- &size, NULL);
- else {
- gnutls_assert();
- return;
- }
-
- if (err == GNUTLS_E_X509_UNSUPPORTED_EXTENSION) {
- /* Check if an alternative name is there */
- print_aki_gn_serial(str, type, cert);
+ err = gnutls_x509_aki_init(&aki);
+ if (err < 0) {
+ addf(str, "error: gnutls_x509_aki_init: %s\n",
+ gnutls_strerror(err));
return;
}
- if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
- addf(str, "error: get_authority_key_id: %s\n",
+ err = gnutls_x509_ext_import_authority_key_id(der, aki, 0);
+ if (err < 0) {
+ addf(str, "error: gnutls_x509_ext_import_authority_key_id: %s\n",
gnutls_strerror(err));
return;
}
- buffer = gnutls_malloc(size);
- if (!buffer) {
- addf(str, "error: malloc: %s\n",
- gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
+ err = gnutls_x509_aki_get_id(aki, &id);
+ if (err == GNUTLS_E_X509_UNSUPPORTED_EXTENSION) {
+ /* Check if an alternative name is there */
+ print_aki_gn_serial(str, aki);
return;
- }
-
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_authority_key_id(cert.crt, buffer,
- &size, NULL);
- else
- err =
- gnutls_x509_crl_get_authority_key_id(cert.crl, buffer,
- &size, NULL);
-
- if (err < 0) {
- gnutls_free(buffer);
- addf(str, "error: get_authority_key_id2: %s\n",
+ } else if (err < 0) {
+ addf(str, "error: gnutls_x509_aki_get_id: %s\n",
gnutls_strerror(err));
return;
}
-
+
adds(str, "\t\t\t");
- _gnutls_buffer_hexprint(str, buffer, size);
+ _gnutls_buffer_hexprint(str, id.data, id.size);
adds(str, "\n");
- gnutls_free(buffer);
+ gnutls_x509_aki_deinit(aki);
}
static void
-print_key_usage(gnutls_buffer_st * str, const char *prefix, int type,
- cert_type_t cert)
+print_key_usage2(gnutls_buffer_st * str, const char *prefix, unsigned int key_usage)
{
- unsigned int key_usage;
- int err;
-
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_key_usage(cert.crt, &key_usage,
- NULL);
- else if (type == TYPE_CRQ)
- err =
- gnutls_x509_crq_get_key_usage(cert.crq, &key_usage,
- NULL);
- else if (type == TYPE_PUBKEY)
- err = gnutls_pubkey_get_key_usage(cert.pubkey, &key_usage);
- else
- return;
-
- if (err < 0) {
- addf(str, "error: get_key_usage: %s\n",
- gnutls_strerror(err));
- return;
- }
-
if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)
addf(str, _("%sDigital signature.\n"), prefix);
if (key_usage & GNUTLS_KEY_NON_REPUDIATION)
}
static void
-print_private_key_usage_period(gnutls_buffer_st * str, const char *prefix,
- int type, cert_type_t cert)
+print_key_usage(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
+{
+ unsigned int key_usage;
+ int err;
+
+ err = gnutls_x509_ext_import_key_usage(der, &key_usage);
+ if (err < 0) {
+ addf(str, "error: get_key_usage: %s\n",
+ gnutls_strerror(err));
+ return;
+ }
+
+ print_key_usage2(str, prefix, key_usage);
+}
+
+static void
+print_private_key_usage_period(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
{
time_t activation, expiration;
int err;
struct tm t;
size_t max;
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_private_key_usage_period(cert.crt,
- &activation,
- &expiration,
- NULL);
- else if (type == TYPE_CRQ)
- err =
- gnutls_x509_crq_get_private_key_usage_period(cert.crq,
- &activation,
- &expiration,
- NULL);
- else
- return;
-
+ err = gnutls_x509_ext_import_private_key_usage_period(der, &activation, &expiration);
if (err < 0) {
addf(str, "error: get_private_key_usage_period: %s\n",
gnutls_strerror(err));
}
-static void print_crldist(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
+static void print_crldist(gnutls_buffer_st * str, gnutls_datum_t *der)
{
- char *buffer = NULL;
- size_t size;
- gnutls_datum_t t;
int err;
int indx;
+ gnutls_x509_crl_dist_points_t dp;
+ unsigned int flags, type;
+ gnutls_datum_t dist;
+
+ err = gnutls_x509_crl_dist_points_init(&dp);
+ if (err < 0) {
+ addf(str, "error: gnutls_x509_crl_dist_points_init: %s\n",
+ gnutls_strerror(err));
+ return;
+ }
+
+ err = gnutls_x509_ext_import_crl_dist_points(der, dp, 0);
+ if (err < 0) {
+ addf(str, "error: gnutls_x509_ext_import_crl_dist_points: %s\n",
+ gnutls_strerror(err));
+ return;
+ }
for (indx = 0;; indx++) {
- size = 0;
err =
- gnutls_x509_crt_get_crl_dist_points(cert, indx, buffer,
- &size, NULL, NULL);
+ gnutls_x509_crl_dist_points_get(dp, indx, &type, &dist, &flags);
if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
return;
- if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ else if (err < 0) {
addf(str, "error: get_crl_dist_points: %s\n",
gnutls_strerror(err));
return;
}
- buffer = gnutls_malloc(size);
- if (!buffer) {
- addf(str, "error: malloc: %s\n",
- gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
- return;
- }
-
- err =
- gnutls_x509_crt_get_crl_dist_points(cert, indx, buffer,
- &size, NULL, NULL);
- if (err < 0) {
- gnutls_free(buffer);
- addf(str, "error: get_crl_dist_points2: %s\n",
- gnutls_strerror(err));
- return;
- }
-
- t.data = (void*)buffer;
- t.size = size;
- print_name(str, "\t\t\t", err, &t);
-
- gnutls_free(buffer);
+ print_name(str, "\t\t\t", type, &dist);
}
}
static void
-print_key_purpose(gnutls_buffer_st * str, const char *prefix, int type,
- cert_type_t cert)
+print_key_purpose(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
{
int indx;
- char *buffer = NULL;
- size_t size;
+ gnutls_datum_t oid;
+ char *p;
int err;
+ gnutls_x509_key_purposes_t purposes;
+
+ err = gnutls_x509_key_purpose_init(&purposes);
+ if (err < 0) {
+ addf(str, "error: gnutls_x509_key_purpose_init: %s\n",
+ gnutls_strerror(err));
+ return;
+ }
- for (indx = 0;; indx++) {
- size = 0;
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_key_purpose_oid(cert.crt,
- indx,
- buffer,
- &size,
- NULL);
- else if (type == TYPE_CRQ)
- err =
- gnutls_x509_crq_get_key_purpose_oid(cert.crq,
- indx,
- buffer,
- &size,
- NULL);
- else
- return;
+ err = gnutls_x509_ext_import_key_purposes(der, purposes, 0);
+ if (err < 0) {
+ addf(str, "error: gnutls_x509_ext_import_key_purposes: %s\n",
+ gnutls_strerror(err));
+ return;
+ }
+ for (indx = 0;; indx++) {
+ err = gnutls_x509_key_purpose_get(purposes, indx, &oid);
if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
return;
- if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
- addf(str, "error: get_key_purpose_oid: %s\n",
+ else if (err < GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ addf(str, "error: gnutls_x509_key_purpose_get: %s\n",
gnutls_strerror(err));
return;
}
- buffer = gnutls_malloc(size);
- if (!buffer) {
- addf(str, "error: malloc: %s\n",
- gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
- return;
- }
-
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_key_purpose_oid(cert.crt,
- indx,
- buffer,
- &size,
- NULL);
- else
- err =
- gnutls_x509_crq_get_key_purpose_oid(cert.crq,
- indx,
- buffer,
- &size,
- NULL);
-
- if (err < 0) {
- gnutls_free(buffer);
- addf(str, "error: get_key_purpose_oid2: %s\n",
- gnutls_strerror(err));
- return;
- }
-
- if (strcmp(buffer, GNUTLS_KP_TLS_WWW_SERVER) == 0)
+ p = (void*)oid.data;
+ if (strcmp(p, GNUTLS_KP_TLS_WWW_SERVER) == 0)
addf(str, _("%s\t\t\tTLS WWW Server.\n"), prefix);
- else if (strcmp(buffer, GNUTLS_KP_TLS_WWW_CLIENT) == 0)
+ else if (strcmp(p, GNUTLS_KP_TLS_WWW_CLIENT) == 0)
addf(str, _("%s\t\t\tTLS WWW Client.\n"), prefix);
- else if (strcmp(buffer, GNUTLS_KP_CODE_SIGNING) == 0)
+ else if (strcmp(p, GNUTLS_KP_CODE_SIGNING) == 0)
addf(str, _("%s\t\t\tCode signing.\n"), prefix);
- else if (strcmp(buffer, GNUTLS_KP_EMAIL_PROTECTION) == 0)
+ else if (strcmp(p, GNUTLS_KP_EMAIL_PROTECTION) == 0)
addf(str, _("%s\t\t\tEmail protection.\n"),
prefix);
- else if (strcmp(buffer, GNUTLS_KP_TIME_STAMPING) == 0)
+ else if (strcmp(p, GNUTLS_KP_TIME_STAMPING) == 0)
addf(str, _("%s\t\t\tTime stamping.\n"), prefix);
- else if (strcmp(buffer, GNUTLS_KP_OCSP_SIGNING) == 0)
+ else if (strcmp(p, GNUTLS_KP_OCSP_SIGNING) == 0)
addf(str, _("%s\t\t\tOCSP signing.\n"), prefix);
- else if (strcmp(buffer, GNUTLS_KP_IPSEC_IKE) == 0)
+ else if (strcmp(p, GNUTLS_KP_IPSEC_IKE) == 0)
addf(str, _("%s\t\t\tIpsec IKE.\n"), prefix);
- else if (strcmp(buffer, GNUTLS_KP_ANY) == 0)
+ else if (strcmp(p, GNUTLS_KP_ANY) == 0)
addf(str, _("%s\t\t\tAny purpose.\n"), prefix);
else
- addf(str, "%s\t\t\t%s\n", prefix, buffer);
-
- gnutls_free(buffer);
+ addf(str, "%s\t\t\t%s\n", prefix, p);
}
+ gnutls_x509_key_purpose_deinit(purposes);
}
static void
-print_basic(gnutls_buffer_st * str, const char *prefix, int type,
- cert_type_t cert)
+print_basic(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
{
int pathlen;
+ unsigned ca;
int err;
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_basic_constraints(cert.crt, NULL,
- NULL, &pathlen);
- else if (type == TYPE_CRQ)
- err =
- gnutls_x509_crq_get_basic_constraints(cert.crq, NULL,
- NULL, &pathlen);
- else
- return;
-
+ err = gnutls_x509_ext_import_basic_constraints(der, &ca, &pathlen);
if (err < 0) {
addf(str, "error: get_basic_constraints: %s\n",
gnutls_strerror(err));
return;
}
- if (err == 0)
+ if (ca == 0)
addf(str, _("%s\t\t\tCertificate Authority (CA): FALSE\n"),
prefix);
else
static void
-print_altname(gnutls_buffer_st * str, const char *prefix,
- unsigned int altname_type, cert_type_t cert)
+print_altname(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
{
unsigned int altname_idx;
- gnutls_datum_t t;
- char *buffer;
- size_t size;
+ gnutls_subject_alt_names_t names;
+ unsigned int type;
+ gnutls_datum_t san;
+ gnutls_datum_t othername;
int err;
- for (altname_idx = 0;; altname_idx++) {
+ err = gnutls_subject_alt_names_init(&names);
+ if (err < 0) {
+ addf(str, "error: gnutls_subject_alt_names_init: %s\n",
+ gnutls_strerror(err));
+ return;
+ }
- buffer = NULL;
- size = 0;
- if (altname_type == TYPE_CRT_SAN)
- err =
- gnutls_x509_crt_get_subject_alt_name(cert.crt,
- altname_idx,
- buffer,
- &size,
- NULL);
- else if (altname_type == TYPE_CRQ_SAN)
- err =
- gnutls_x509_crq_get_subject_alt_name(cert.crq,
- altname_idx,
- buffer,
- &size,
- NULL,
- NULL);
- else if (altname_type == TYPE_CRT_IAN)
- err =
- gnutls_x509_crt_get_issuer_alt_name(cert.crt,
- altname_idx,
- buffer,
- &size,
- NULL);
- else
- return;
+ err = gnutls_x509_ext_import_subject_alt_names(der, names, 0);
+ if (err < 0) {
+ addf(str, "error: gnutls_x509_ext_import_subject_alt_names: %s\n",
+ gnutls_strerror(err));
+ return;
+ }
+ for (altname_idx = 0;; altname_idx++) {
+ err = gnutls_subject_alt_names_get(names, altname_idx,
+ &type, &san, &othername);
if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
break;
- if (err < 0 && err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ else if (err < 0) {
addf(str,
- "error: get_subject/issuer_alt_name: %s\n",
+ "error: gnutls_subject_alt_names_get: %s\n",
gnutls_strerror(err));
return;
}
- buffer = gnutls_malloc(size);
- if (!buffer) {
- addf(str, "error: malloc: %s\n",
- gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
- return;
- }
-
- if (altname_type == TYPE_CRT_SAN) {
- err =
- gnutls_x509_crt_get_subject_alt_name(cert.crt,
- altname_idx,
- buffer,
- &size,
- NULL);
- } else if (altname_type == TYPE_CRQ_SAN) {
- err =
- gnutls_x509_crq_get_subject_alt_name(cert.crq,
- altname_idx,
- buffer,
- &size,
- NULL,
- NULL);
- } else if (altname_type == TYPE_CRT_IAN) {
- err =
- gnutls_x509_crt_get_issuer_alt_name(cert.crt,
- altname_idx,
- buffer,
- &size,
- NULL);
- }
- if (err < 0) {
- gnutls_free(buffer);
+ if (type == GNUTLS_SAN_OTHERNAME) {
addf(str,
- "error: get_subject/issuer_alt_name2: %s\n",
- gnutls_strerror(err));
- return;
- }
-
- if (err == GNUTLS_SAN_OTHERNAME) {
- char *oid = NULL;
- size_t oidsize;
-
- oidsize = 0;
- if (altname_type == TYPE_CRT_SAN)
- err =
- gnutls_x509_crt_get_subject_alt_othername_oid
- (cert.crt, altname_idx, oid, &oidsize);
- else if (altname_type == TYPE_CRQ_SAN)
- err =
- gnutls_x509_crq_get_subject_alt_othername_oid
- (cert.crq, altname_idx, oid, &oidsize);
- else if (altname_type == TYPE_CRT_IAN)
- err =
- gnutls_x509_crt_get_issuer_alt_othername_oid
- (cert.crt, altname_idx, oid, &oidsize);
-
- if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
- gnutls_free(buffer);
- addf(str,
- "error: get_subject/issuer_alt_othername_oid: %s (%d)\n",
- gnutls_strerror(err), err);
- return;
- }
-
- oid = gnutls_malloc(oidsize);
- if (!oid) {
- gnutls_free(buffer);
- addf(str, "error: malloc: %s\n",
- gnutls_strerror
- (GNUTLS_E_MEMORY_ERROR));
- return;
- }
-
- if (altname_type == TYPE_CRT_SAN)
- err =
- gnutls_x509_crt_get_subject_alt_othername_oid
- (cert.crt, altname_idx, oid, &oidsize);
- else if (altname_type == TYPE_CRQ_SAN)
- err =
- gnutls_x509_crq_get_subject_alt_othername_oid
- (cert.crq, altname_idx, oid, &oidsize);
- else if (altname_type == TYPE_CRT_IAN)
- err =
- gnutls_x509_crt_get_issuer_alt_othername_oid
- (cert.crt, altname_idx, oid, &oidsize);
-
- if (err < 0) {
- gnutls_free(buffer);
- gnutls_free(oid);
- addf(str,
- "error: get_subject_alt_othername_oid2: %s\n",
- gnutls_strerror(err));
- return;
- }
-
- if (err == GNUTLS_SAN_OTHERNAME_XMPP) {
- if (strlen(buffer) != size) {
- adds(str,
- _
- ("warning: altname contains an embedded NUL, "
- "replacing with '!'\n"));
- while (strlen(buffer) < size)
- buffer[strlen(buffer)] =
- '!';
- }
-
- addf(str,
- _("%s\t\t\tXMPP Address: %.*s\n"),
- prefix, (int) size, buffer);
- } else {
- addf(str,
- _("%s\t\t\totherName OID: %.*s\n"),
- prefix, (int) oidsize, oid);
- addf(str, _("%s\t\t\totherName DER: "),
+ _("%s\t\t\totherName OID: %.*s\n"),
+ prefix, (int)othername.size, (char*)othername.data);
+ addf(str, _("%s\t\t\totherName DER: "),
prefix);
- _gnutls_buffer_hexprint(str, buffer, size);
- addf(str, _("\n%s\t\t\totherName ASCII: "),
+ _gnutls_buffer_hexprint(str, san.data, san.size);
+ addf(str, _("\n%s\t\t\totherName ASCII: "),
prefix);
- _gnutls_buffer_asciiprint(str, buffer,
- size);
+ _gnutls_buffer_asciiprint(str, (char*)san.data, san.size);
addf(str, "\n");
- }
- gnutls_free(oid);
} else {
char pfx[16];
- t.data = (void*)buffer;
- t.size = size;
snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix);
- print_name(str, pfx, err, &t);
+ print_name(str, pfx, type, &san);
}
-
- gnutls_free(buffer);
}
+ gnutls_subject_alt_names_deinit(names);
}
static void
}
}
-static void
-print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
- cert_type_t cert)
+struct ext_indexes_st {
+ int san;
+ int ian;
+ int proxy;
+ int basic;
+ int keyusage;
+ int keypurpose;
+ int ski;
+ int aki, nc;
+ int crldist, pkey_usage_period;
+};
+
+static void print_extension(gnutls_buffer_st * str, const char *prefix,
+ struct ext_indexes_st *idx, const char *oid,
+ unsigned critical, gnutls_datum_t *der)
{
- unsigned i, j;
int err;
- int san_idx = 0;
- int ian_idx = 0;
- int proxy_idx = 0;
- int basic_idx = 0;
- int keyusage_idx = 0;
- int keypurpose_idx = 0;
- int ski_idx = 0;
- int aki_idx = 0, nc_idx = 0;
- int crldist_idx = 0, pkey_usage_period_idx = 0;
- gnutls_datum_t der = {NULL, 0};
+ unsigned j;
char pfx[16];
- for (i = 0;; i++) {
- char oid[MAX_OID_SIZE] = "";
- size_t sizeof_oid = sizeof(oid);
- unsigned int critical;
+ if (strcmp(oid, "2.5.29.19") == 0) {
+ if (idx->basic) {
+ addf(str,
+ "error: more than one basic constraint\n");
+ }
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_extension_info(cert.crt, i,
- oid,
- &sizeof_oid,
- &critical);
+ addf(str, _("%s\t\tBasic Constraints (%s):\n"),
+ prefix,
+ critical ? _("critical") : _("not critical"));
- else if (type == TYPE_CRQ)
- err =
- gnutls_x509_crq_get_extension_info(cert.crq, i,
- oid,
- &sizeof_oid,
- &critical);
- else {
- gnutls_assert();
+ print_basic(str, prefix, der);
+ idx->basic++;
+
+ } else if (strcmp(oid, "2.5.29.14") == 0) {
+ if (idx->ski) {
+ addf(str,
+ "error: more than one SKI extension\n");
+ }
+
+ addf(str,
+ _("%s\t\tSubject Key Identifier (%s):\n"),
+ prefix,
+ critical ? _("critical") : _("not critical"));
+
+ print_ski(str, der);
+
+ idx->ski++;
+ } else if (strcmp(oid, "2.5.29.32") == 0) {
+ struct gnutls_x509_policy_st policy;
+ gnutls_x509_policies_t policies;
+ const char *name;
+ int x;
+
+ err = gnutls_x509_policies_init(&policies);
+ if (err < 0) {
+ addf(str,
+ "error: certificate policies: %s\n",
+ gnutls_strerror(err));
return;
}
+ err = gnutls_x509_ext_import_policies(der, policies, 0);
if (err < 0) {
- if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
- break;
- addf(str, "error: get_extension_info: %s\n",
+ addf(str,
+ "error: certificate policies import: %s\n",
gnutls_strerror(err));
- continue;
+ return;
}
- if (i == 0)
- addf(str, _("%s\tExtensions:\n"), prefix);
+ for (x = 0;; x++) {
+ err = gnutls_x509_policies_get(policies, x, &policy);
+ if (err ==
+ GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ break;
- if (strcmp(oid, "2.5.29.19") == 0) {
- if (basic_idx) {
+ if (err < 0) {
addf(str,
- "error: more than one basic constraint\n");
- continue;
+ "error: certificate policy: %s\n",
+ gnutls_strerror(err));
+ break;
}
- addf(str, _("%s\t\tBasic Constraints (%s):\n"),
- prefix,
- critical ? _("critical") : _("not critical"));
-
- print_basic(str, prefix, type, cert);
-
- basic_idx++;
- } else if (strcmp(oid, "2.5.29.14") == 0) {
- if (ski_idx) {
+ if (x == 0)
addf(str,
- "error: more than one SKI extension\n");
- continue;
+ "%s\t\tCertificate Policies (%s):\n",
+ prefix,
+ critical ? _("critical") :
+ _("not critical"));
+
+ addf(str, "%s\t\t\t%s\n", prefix, policy.oid);
+ for (j = 0; j < policy.qualifiers; j++) {
+ if (policy.qualifier[j].type ==
+ GNUTLS_X509_QUALIFIER_URI)
+ name = "URI";
+ else if (policy.qualifier[j].
+ type ==
+ GNUTLS_X509_QUALIFIER_NOTICE)
+ name = "Note";
+ else
+ name = "Unknown qualifier";
+ addf(str, "%s\t\t\t\t%s: %s\n",
+ prefix, name,
+ policy.qualifier[j].data);
}
+ gnutls_x509_policy_release(&policy);
+ }
+ gnutls_x509_policies_deinit(policies);
+ } else if (strcmp(oid, "2.5.29.35") == 0) {
+ if (idx->aki) {
addf(str,
- _("%s\t\tSubject Key Identifier (%s):\n"),
- prefix,
- critical ? _("critical") : _("not critical"));
-
- if (type == TYPE_CRT)
- print_ski(str, cert.crt);
-
- ski_idx++;
- } else if (strcmp(oid, "2.5.29.32") == 0) {
- struct gnutls_x509_policy_st policy;
- const char *name;
- int x;
-
- for (x = 0;; x++) {
- err =
- gnutls_x509_crt_get_policy(cert.crt, x,
- &policy,
- &critical);
- if (err ==
- GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
- break;
-
- if (err < 0) {
- addf(str,
- "error: certificate policy: %s\n",
- gnutls_strerror(err));
- break;
- }
-
- if (x == 0)
- addf(str,
- "%s\t\tCertificate Policies (%s):\n",
- prefix,
- critical ? _("critical") :
- _("not critical"));
-
- addf(str, "%s\t\t\t%s\n", prefix,
- policy.oid);
- for (j = 0; j < policy.qualifiers; j++) {
- if (policy.qualifier[j].type ==
- GNUTLS_X509_QUALIFIER_URI)
- name = "URI";
- else if (policy.qualifier[j].
- type ==
- GNUTLS_X509_QUALIFIER_NOTICE)
- name = "Note";
- else
- name = "Unknown qualifier";
- addf(str, "%s\t\t\t\t%s: %s\n",
- prefix, name,
- policy.qualifier[j].data);
- }
+ "error: more than one AKI extension\n");
+ }
- gnutls_x509_policy_release(&policy);
- }
- } else if (strcmp(oid, "2.5.29.35") == 0) {
+ addf(str,
+ _("%s\t\tAuthority Key Identifier (%s):\n"),
+ prefix,
+ critical ? _("critical") : _("not critical"));
- if (aki_idx) {
- addf(str,
- "error: more than one AKI extension\n");
- continue;
- }
+ print_aki(str, der);
+ idx->aki++;
+ } else if (strcmp(oid, "2.5.29.15") == 0) {
+ if (idx->keyusage) {
addf(str,
- _("%s\t\tAuthority Key Identifier (%s):\n"),
- prefix,
- critical ? _("critical") : _("not critical"));
-
- if (type == TYPE_CRT)
- print_aki(str, TYPE_CRT, cert);
-
- aki_idx++;
- } else if (strcmp(oid, "2.5.29.15") == 0) {
- if (keyusage_idx) {
- addf(str,
- "error: more than one key usage extension\n");
- continue;
- }
+ "error: more than one key usage extension\n");
+ }
- addf(str, _("%s\t\tKey Usage (%s):\n"), prefix,
+ addf(str, _("%s\t\tKey Usage (%s):\n"), prefix,
critical ? _("critical") : _("not critical"));
- snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix);
- print_key_usage(str, pfx, type, cert);
-
- keyusage_idx++;
- } else if (strcmp(oid, "2.5.29.16") == 0) {
- if (pkey_usage_period_idx) {
- addf(str,
- "error: more than one private key usage period extension\n");
- continue;
- }
+ snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix);
+ print_key_usage(str, pfx, der);
+ idx->keyusage++;
+ } else if (strcmp(oid, "2.5.29.16") == 0) {
+ if (idx->pkey_usage_period) {
addf(str,
- _("%s\t\tPrivate Key Usage Period (%s):\n"),
- prefix,
- critical ? _("critical") : _("not critical"));
-
- print_private_key_usage_period(str, prefix, type,
- cert);
-
- pkey_usage_period_idx++;
- } else if (strcmp(oid, "2.5.29.37") == 0) {
- if (keypurpose_idx) {
- addf(str,
- "error: more than one key purpose extension\n");
- continue;
- }
+ "error: more than one private key usage period extension\n");
+ }
- addf(str, _("%s\t\tKey Purpose (%s):\n"), prefix,
- critical ? _("critical") : _("not critical"));
+ addf(str,
+ _("%s\t\tPrivate Key Usage Period (%s):\n"),
+ prefix,
+ critical ? _("critical") : _("not critical"));
- print_key_purpose(str, prefix, type, cert);
- keypurpose_idx++;
- } else if (strcmp(oid, "2.5.29.17") == 0) {
- if (san_idx) {
- addf(str,
- "error: more than one SKI extension\n");
- continue;
- }
+ print_private_key_usage_period(str, prefix, der);
+ idx->pkey_usage_period++;
+ } else if (strcmp(oid, "2.5.29.37") == 0) {
+ if (idx->keypurpose) {
addf(str,
- _("%s\t\tSubject Alternative Name (%s):\n"),
- prefix,
- critical ? _("critical") : _("not critical"));
+ "error: more than one key purpose extension\n");
+ }
- print_altname(str, prefix, type, cert);
+ addf(str, _("%s\t\tKey Purpose (%s):\n"), prefix,
+ critical ? _("critical") : _("not critical"));
- san_idx++;
- } else if (strcmp(oid, "2.5.29.18") == 0) {
- if (ian_idx) {
- addf(str,
- "error: more than one Issuer AltName extension\n");
- continue;
- }
+ print_key_purpose(str, prefix, der);
+ idx->keypurpose++;
+ } else if (strcmp(oid, "2.5.29.17") == 0) {
+ if (idx->san) {
+ addf(str,
+ "error: more than one SKI extension\n");
+ }
+ addf(str,
+ _("%s\t\tSubject Alternative Name (%s):\n"),
+ prefix,
+ critical ? _("critical") : _("not critical"));
+ print_altname(str, prefix, der);
+ idx->san++;
+ } else if (strcmp(oid, "2.5.29.18") == 0) {
+ if (idx->ian) {
addf(str,
- _("%s\t\tIssuer Alternative Name (%s):\n"),
- prefix,
- critical ? _("critical") : _("not critical"));
+ "error: more than one Issuer AltName extension\n");
+ }
- print_altname(str, prefix, TYPE_CRT_IAN, cert);
+ addf(str,
+ _("%s\t\tIssuer Alternative Name (%s):\n"),
+ prefix,
+ critical ? _("critical") : _("not critical"));
- ian_idx++;
- } else if (strcmp(oid, "2.5.29.31") == 0) {
- if (crldist_idx) {
- addf(str,
- "error: more than one CRL distribution point\n");
- continue;
- }
+ print_altname(str, prefix, der);
+ idx->ian++;
+ } else if (strcmp(oid, "2.5.29.31") == 0) {
+ if (idx->crldist) {
addf(str,
- _("%s\t\tCRL Distribution points (%s):\n"),
- prefix,
- critical ? _("critical") : _("not critical"));
+ "error: more than one CRL distribution point\n");
+ }
- if (type == TYPE_CRT)
- print_crldist(str, cert.crt);
- crldist_idx++;
- } else if (strcmp(oid, "1.3.6.1.5.5.7.1.14") == 0) {
- if (proxy_idx) {
- addf(str,
- "error: more than one proxy extension\n");
- continue;
- }
+ addf(str,
+ _("%s\t\tCRL Distribution points (%s):\n"),
+ prefix,
+ critical ? _("critical") : _("not critical"));
+ print_crldist(str, der);
+ idx->crldist++;
+ } else if (strcmp(oid, "1.3.6.1.5.5.7.1.14") == 0) {
+ if (idx->proxy) {
addf(str,
+ "error: more than one proxy extension\n");
+ }
+
+ addf(str,
_
- ("%s\t\tProxy Certificate Information (%s):\n"),
- prefix,
- critical ? _("critical") : _("not critical"));
+ ("%s\t\tProxy Certificate Information (%s):\n"),
+ prefix,
+ critical ? _("critical") : _("not critical"));
- if (type == TYPE_CRT)
- print_proxy(str, cert.crt);
+ print_proxy(str, der);
- proxy_idx++;
- } else if (strcmp(oid, "1.3.6.1.5.5.7.1.1") == 0) {
- addf(str, _("%s\t\tAuthority Information "
- "Access (%s):\n"), prefix,
- critical ? _("critical") : _("not critical"));
+ idx->proxy++;
+ } else if (strcmp(oid, "1.3.6.1.5.5.7.1.1") == 0) {
+ addf(str, _("%s\t\tAuthority Information "
+ "Access (%s):\n"), prefix,
+ critical ? _("critical") : _("not critical"));
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_extension_data2
- (cert.crt, i, &der);
- else if (type == TYPE_CRQ)
- err =
- gnutls_x509_crq_get_extension_data2
- (cert.crq, i, &der);
- else {
- gnutls_assert();
- return;
- }
+ print_aia(str, der);
+ } else if (strcmp(oid, "2.5.29.30") == 0) {
+ if (idx->nc) {
+ addf(str,
+ "error: more than one name constraints extension\n");
+ }
+ idx->nc++;
- if (err < 0) {
- addf(str,
- "error: get_extension_data2: %s\n",
- gnutls_strerror(err));
- continue;
- }
+ addf(str, _("%s\t\tName Constraints (%s):\n"), prefix,
+ critical ? _("critical") : _("not critical"));
- print_aia(str, &der);
+ print_nc(str, prefix, der);
+ } else {
+ addf(str, _("%s\t\tUnknown extension %s (%s):\n"),
+ prefix, oid,
+ critical ? _("critical") : _("not critical"));
- _gnutls_free_datum(&der);
- } else if (strcmp(oid, "2.5.29.30") == 0) {
- if (nc_idx) {
- addf(str,
- "error: more than one name constraints extension\n");
- continue;
- }
- nc_idx++;
+ addf(str, _("%s\t\t\tASCII: "), prefix);
+ _gnutls_buffer_asciiprint(str, (char*)der->data, der->size);
- addf(str, _("%s\t\tName Constraints (%s):\n"), prefix,
- critical ? _("critical") : _("not critical"));
+ addf(str, "\n");
+ addf(str, _("%s\t\t\tHexdump: "), prefix);
+ _gnutls_buffer_hexprint(str, (char*)der->data, der->size);
+ adds(str, "\n");
+ }
+}
- if (type == TYPE_CRT)
- print_nc(str, prefix, cert.crt);
- } else {
+static void
+print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
+ cert_type_t cert)
+{
+ unsigned i;
+ int err;
+ gnutls_datum_t der = {NULL, 0};
+ struct ext_indexes_st idx;
- addf(str, _("%s\t\tUnknown extension %s (%s):\n"),
- prefix, oid,
- critical ? _("critical") : _("not critical"));
+ memset(&idx, 0, sizeof(idx));
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_extension_data2
- (cert.crt, i, &der);
- else if (type == TYPE_CRQ)
- err =
- gnutls_x509_crq_get_extension_data2
- (cert.crq, i, &der);
- else {
- gnutls_assert();
- return;
- }
+ for (i = 0;; i++) {
+ char oid[MAX_OID_SIZE] = "";
+ size_t sizeof_oid = sizeof(oid);
+ unsigned int critical;
- if (err < 0) {
- addf(str,
- "error: get_extension_data2: %s\n",
- gnutls_strerror(err));
- continue;
- }
+ if (type == TYPE_CRT)
+ err =
+ gnutls_x509_crt_get_extension_info(cert.crt, i,
+ oid,
+ &sizeof_oid,
+ &critical);
- addf(str, _("%s\t\t\tASCII: "), prefix);
- _gnutls_buffer_asciiprint(str, (char*)der.data, der.size);
- addf(str, "\n");
+ else if (type == TYPE_CRQ)
+ err =
+ gnutls_x509_crq_get_extension_info(cert.crq, i,
+ oid,
+ &sizeof_oid,
+ &critical);
+ else {
+ gnutls_assert();
+ return;
+ }
- addf(str, _("%s\t\t\tHexdump: "), prefix);
- _gnutls_buffer_hexprint(str, (char*)der.data, der.size);
- adds(str, "\n");
+ if (err < 0) {
+ if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ break;
+ addf(str, "error: get_extension_info: %s\n",
+ gnutls_strerror(err));
+ continue;
+ }
+
+ if (i == 0)
+ addf(str, _("%s\tExtensions:\n"), prefix);
- _gnutls_free_datum(&der);
+ if (type == TYPE_CRT)
+ err = gnutls_x509_crt_get_extension_data2(cert.crt, i, &der);
+ else
+ err = gnutls_x509_crq_get_extension_data2(cert.crq, i, &der);
+
+ if (err < 0) {
+ der.data = NULL;
+ der.size = 0;
}
+
+ print_extension(str, prefix, &idx, oid, critical, &der);
}
}
* gnutls_x509_crt_print:
* @cert: The structure to be printed
* @format: Indicate the format to use
- * @out: Newly allocated datum with (0) terminated string.
+ * @out: Newly allocated datum with zero terminated string.
*
* This function will pretty print a X.509 certificate, suitable for
* display to a human.
crl_nr++;
} else if (strcmp(oid, "2.5.29.35") == 0) {
- cert_type_t ccert;
+ gnutls_datum_t der;
if (aki_idx) {
addf(str,
critical ? _("critical") :
_("not critical"));
- ccert.crl = crl;
- print_aki(str, TYPE_CRL, ccert);
+ err = gnutls_x509_crl_get_extension_data2(crl, i, &der);
+ if (err < 0) {
+ addf(str,
+ "error: get_extension_data2: %s\n",
+ gnutls_strerror(err));
+ continue;
+ }
+ print_aki(str, &der);
+ gnutls_free(der.data);
aki_idx++;
} else {
- char *buffer;
- size_t extlen = 0;
+ gnutls_datum_t der;
addf(str,
_("\t\tUnknown extension %s (%s):\n"),
_("not critical"));
err =
- gnutls_x509_crl_get_extension_data(crl,
- i,
- NULL,
- &extlen);
- if (err < 0) {
- addf(str,
- "error: get_extension_data: %s\n",
- gnutls_strerror(err));
- continue;
- }
-
- buffer = gnutls_malloc(extlen);
- if (!buffer) {
- addf(str, "error: malloc: %s\n",
- gnutls_strerror
- (GNUTLS_E_MEMORY_ERROR));
- continue;
- }
-
- err =
- gnutls_x509_crl_get_extension_data(crl,
+ gnutls_x509_crl_get_extension_data2(crl,
i,
- buffer,
- &extlen);
+ &der);
if (err < 0) {
- gnutls_free(buffer);
addf(str,
"error: get_extension_data2: %s\n",
gnutls_strerror(err));
}
adds(str, _("\t\t\tASCII: "));
- _gnutls_buffer_asciiprint(str, buffer,
- extlen);
+ _gnutls_buffer_asciiprint(str, (char*)der.data, der.size);
adds(str, "\n");
adds(str, _("\t\t\tHexdump: "));
- _gnutls_buffer_hexprint(str, buffer,
- extlen);
+ _gnutls_buffer_hexprint(str, der.data, der.size);
adds(str, "\n");
- gnutls_free(buffer);
+ gnutls_free(der.data);
}
}
}
* gnutls_x509_crl_print:
* @crl: The structure to be printed
* @format: Indicate the format to use
- * @out: Newly allocated datum with (0) terminated string.
+ * @out: Newly allocated datum with zero terminated string.
*
* This function will pretty print a X.509 certificate revocation
* list, suitable for display to a human.
* gnutls_x509_crq_print:
* @crq: The structure to be printed
* @format: Indicate the format to use
- * @out: Newly allocated datum with (0) terminated string.
+ * @out: Newly allocated datum with zero terminated string.
*
* This function will pretty print a certificate request, suitable for
* display to a human.
size_t size = sizeof(buffer);
int ret;
unsigned int usage;
- cert_type_t ccert;
-
- ccert.pubkey = pubkey;
ret = gnutls_pubkey_get_key_usage(pubkey, &usage);
if (ret < 0) {
adds(str, "\n");
adds(str, _("Public Key Usage:\n"));
- print_key_usage(str, "\t", TYPE_PUBKEY, ccert);
+ print_key_usage2(str, "\t", pubkey->key_usage);
ret = gnutls_pubkey_get_key_id(pubkey, 0, buffer, &size);
if (ret < 0) {
* gnutls_pubkey_print:
* @pubkey: The structure to be printed
* @format: Indicate the format to use
- * @out: Newly allocated datum with (0) terminated string.
+ * @out: Newly allocated datum with zero terminated string.
*
* This function will pretty print public key information, suitable for
* display to a human.
return ret;
}
+
+/**
+ * gnutls_x509_ext_print:
+ * @exts: The structures to be printed
+ * @exts_size: the number of available structures
+ * @format: Indicate the format to use
+ * @out: Newly allocated datum with zero terminated string.
+ *
+ * This function will pretty print X.509 certificate extensions,
+ * suitable for display to a human.
+ *
+ * The output @out needs to be deallocated using gnutls_free().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_x509_ext_print(gnutls_x509_ext_st *exts, unsigned int exts_size,
+ gnutls_certificate_print_formats_t format,
+ gnutls_datum_t * out)
+{
+ gnutls_buffer_st str;
+ struct ext_indexes_st idx;
+ int ret;
+ unsigned i;
+
+ memset(&idx, 0, sizeof(idx));
+ _gnutls_buffer_init(&str);
+
+ for (i=0;i<exts_size;i++)
+ print_extension(&str, "\t", &idx, (char*)exts[i].oid, exts[i].critical, &exts[i].data);
+
+ _gnutls_buffer_append_data(&str, "\x00", 1);
+
+ ret = _gnutls_buffer_to_datum(&str, out);
+ if (out->size > 0)
+ out->size--;
+ return ret;
+}